//========================================================================
//  SE5 AI Orders - Ships - Captain Kwok's Balance Mod v125+
//========================================================================
//
// Balance Mod Changes:
// --------------------
// v1.29 Changed - AI players will increase their attack range when playing in Team Mode
//       Changed - AI players will only conduct refits on planets with a Space Yard and Resupply Depot
//       Fixed   - Error in the atmosphere returned for possible population transport destinations
//       Fixed   - Did not update the Minister for opening warp points for the reduction in the Quantum Resonator range
//       Changed - Added random factor in target selection to reduce predictability of attack locations (planets only)
//       Fixed   - Error that prevented fleets from moving to the system of a demand request
//       Changed - Computer players will use fewer fleets when in team mode (v129b)
// v1.27 Changed - Updated factors for AI players to change their fleet formation sizes
//       Changed - Created different strategies for assigning combat ships to task forces (sequential, spread, spread by type)
//       Changed - All ship roles in a task force will always be core (removed escort, picket)
//       Changed - AI patrol ships will no longer join fleets
//       Changed - AI patrol ships will choose the closest patrol location to its own location first
//       Added   - Due to issue with marked minefields not always clearing when there are 0 mines, fleets will sometimes attack move to those sectors to remove the block
//       Added   - Added Fx[Send_Ship_To_Clear_Minefield] to send individual ships to clear false minefields per above
// v1.25 Fixed   - Added a workaround for when a fleet ID doesn't sync with the fleet index returned from Sys_Get_Empire_Fleet_Count
//       Changed - Individual ships can now follow up on Requests
//       Fixed   - Corrected assignment of ships as task force leaders
//       Changed - Add some variation for ships being sent on patrol to add a random stop in the system before heading to the final destination (increase sensor coverage)
//       Changed - Removed Fx[Is_Enemy_Present_At_Location] since similar function was in global functions script
//       Changed - Adjusted target strength modifiers to encourage AI players to be more aggressive
// v1.22 Fixed   - Error in orders to move to Space Yard Hub was causing ships to accumulate in the edges of systems
//       Changed - Reduced the number of targets AI ships cycle through by limiting some types to attack in-system only
//       Changed - Patrol ships for AI players will not join fleets
//       Fixed   - Occasional bug where a colonizer with a damaged colony module would get stuck in the orbit of its target for colonization
// v1.21 Fixed   - Sometimes AIs would order ships to scrap when they should have been retrofit
//       Added   - Support for AI to actively defend targeted locations
// v1.20 Changed - Updated design type name references
//       Added   - Fx[Load_Ship_Data], Fx[Save_Ship_Data] to save a simple turn-to-turn status for an empire's ships
//       Fixed   - Remote Resource ships weren't not being sent to the closest asteroid fields
//       Changed - Script optimization for resupply/retrofit/mothball checks
//       Changed - Improvements to AI fleet size distribution for attack and defense fleets
//       Added   - AI won't attack a player it said it would (usually)
//       Added   - AI will potentially attack a player it said it might (if opportunity exists)
//       Fixed   - AI players would create new fleets at homeworlds they no longer possessed
//       Changed - Improvements for ships joining fleets
//       Changed - Improvements to AI Fleet management, dynamic fleet sizing
//       Changed - Updates for task force designation, dynamic formations
// v1.19 Changed - The AI was sometimes leaving its Warp Point Openers on a newly created warp point that could be attacked
//       Added   - New Fx[Send_Ship_To_Escort] to synchronize escorts with their targets
//       Added   - Fleet order to send fleets to border systems on occasion
//       Changed - Made improvements to how the AI selects planets to load cargo from for unit launching etc.
//       Fixed   - Sometimes the AI was dropping units in the wrong location
//       Fixed   - The AI would sometimes build too many defense bases at one location instead of spreading them out
//       Changed - Improved the AI's distribution of ships in fleets (v1.19a)
//       Fixed   - Error in task force strategy selection (v1.19a)
//       Changed - Made improvements to the selection of planets to colonize (v1.19a)
//       Changed - More of an effort will be made by a Colony Ship to bring defensive units to new colonies (v1.19a)
//       Changed - Minor improvements to target selection for fleets (v1.19a)
//       Fixed   - Sometimes the AI when using single attack ships would attack without ordnance (v1.19a)
//       Added   - Fx[Send_Ship_To_Roam] to handle ships in isolated systems (due to events etc.) (v1.19c)
//       Changed - Made improvements to the AI's mothballing and scrapping functions (v1.19c)
//       Added   - Added new rules for the Ships (All) - Naming minister to understand player wildcards (v1.19c)
//       Changed - AI players were scrapping ships too frequently (v1.19d)
//       Changed - Added checks for certain AI ships to check if they had a needed functional component working (v1.19f)
//       Added   - Cargo Transports will distribute Fighters to colonies in addition to Weapon Platforms (v1.19g)
//       Changed - Increased likelihood of older ships being scrapped (v1.19g)
//       Changed - Made adjustments to which ships are selected for mothballing (v1.19g)
//       Fixed   - Sometimes ships/bases wouldn't drop their cargo before attempting to retrofit (v1.19g)
//       Changed - AI Colony Ships will check to see if they are closest colonizer to a selected colonization target (v1.19h)
//       Fixed   - Ships in fleets could be scrapped or retrofit when the respective ministers were off (v1.19h)
//       Changed - AI fleets will more actively engage soft targets first (v1.19h)
//       Changed - AI fleets will retreat to key colonies in a system if enemy forces present are much stronger (v1.19h)
//       Changed - AI transports and layers will attempt to use leftover movement points after dropping off their cargo (v1.19h)
//       Changed - Improvements to how AI players decide where to pick up cargo (v1.19h)
//       Changed - Allow fleets to designate time to retrofit ships (v1.19h)
//       Fixed   - Sometimes a fleet would be reported with no orders, when in fact it had some (v1.19h)
//       Fixed   - Standalone Fighter and Drone groups weren't receiving orders (v1.19h)
//       Changed - AI fleets will monitor their mine sweeping capabilities and make checks for possible enemy minefields before attacking (v1.19i)
//       Changed - Improved AI's target selection for ships and fleets (v1.19i)
//       Fixed   - AI had stopped building Remote Bases (v1.19i)
//       Removed - Fx[Does_Ship_Need_Repair] and added to Script_AI_GlobalFunctions.txt (v1.19i)
//       Added   - Fx[Send_Ship_To_Repair] to order a ship to a space yard or self-destruct (v1.19i)
//       Fixed   - Sometimes remote SY base would be mothballed but never unmothballed (v1.19i)
//       Changed - Added support for finite resource games and remote resource gathering (v1.19j)
//       Added   - Scout Ship design types will sometimes choose attack versus survey (v1.19j)
//       Added   - Space Yard and Repair Ships can now receive orders to help repair stacks of retrofitting ships (v1.19j)
//       Changed - Fleets will try to retrofit at Space Yard Hubs only (v1.19j)
//       Fixed   - AI Warp Point Openers were sometimes picking invalid targets (v1.19j)
//       Changed - Made improvements to Storm/Planet/Storm Destroyer orders (v1.19j)
//       Changed - AI will attempt to analyze foreign ships it obtains that are not obsolete (v1.19j)
// v1.18 Fixed   - Prevented the AI from trying to retrofit vehicle hulls they did not have racial traits for
// v1.17 Fixed   - The AI was sometimes setting its task force strategies incorrectly
//       Changed - Adjusted conditions for pick-up locations of Population Transports to be based on percent capacity
//       Changed - Improvements to the selection of pickup and launch locations for unit layers
//       Changed - Improved the selection of fleets for ships to join
//       Changed - Ships with join fleet orders will have their destination updated each turn
// v1.16 Fixed   - Minister for warp point creation will check for maximum distance
//       Fixed   - Minister for planet destruction will check for planet size
// v1.15 Changed - Revised Minister - Medical Ships operation
//       Changed - Activated Stellar Manipulation ministers
//       Added   - New Fx[Evaluate_Current_Orders] to improve the AI's ability to adapt to changes
//       Added   - Ordnance check as part of the resupply routine
//       Fixed   - Sometimes bases were still getting move orders when ordered to retrofit
//       Added   - New Fx[Minister_Naming] to re-name ships automatically
//       Fixed   - Sometimes the Population Transport Minister dropped non-breathing population on a undomed planet
//       Changed - Population Transport Minister will prioritize planets with a low percentage of population, rather than absolute population
//       Fixed   - The AI was not following maximum unit drop distribution
//       Changed - The AI will use Cargo Transports (or Colony Ships) as Population Transports if population is required urgently
//       Changed - Made improvements to the remote mining minister
//       Fixed   - AI Cargo Transports were not always dropping their cargo
//       Fixed   - AI Cargo Transports will not attempt to drop cargo on a location that can't hold it
//       Changed - Fleets will consider their range before attacking more distant targets
//       Fixed   - Sometimes AI fleets would resupply too early
//       Added   - New Fx[Minister_Mothballing] to mothball AI ships/bases as required
//       Changed - Allowed explorer ships to stack survey orders after explore orders
// v1.14 Added   - Support for new AI ship size distribution scheme
//       Fixed   - Sometimes fleets were stacking attack orders that tied them up for too long
//       Added   - New fleet order to visit colonies in shared systems
//       Changed - Re-activated Fx[Ship_Order_Drop_Cargo] to ferry Weapon Platforms to defense systems
// v1.13 Changed - Attack and defense locations are removed when a fleet receives an order
//       Fixed   - Error in nearby enemy target selection for fleets
//       Added   - New Fx[Ship_Order_Go_To_Nearest_Colony]
//       Changed - Small tweaks to Fx[Ship_Order_Launch_Units] to improve remote unit distribution
//       Added   - Fleet order to follow up in systems where the AI had made demands for an enemy to remove its ships or colonies
//       Fixed   - Neutral players should not order their fleets to transit warp points
// v1.12 Changed - Reduced the base demand for support ships in fleets
//       Fixed   - Sometimes AI fleets were stacking attack orders
//       Changed - Adjusted Fx[Is_Enemy_Present_At_Location] to include the AI's systems to avoid
//       Fixed   - Sometimes resource ships were attempting to remotely mine in occupied sectors
//       Changed - AI will designate fleets for either attack or defense
//       Changed - General improvements to Fx[Give_Fleet_Specific_Orders]
//       Removed - Retrofit check for ships in fleets
// v1.11 Fixed   - Error in lone attack ship routine
//       Changed - Re-wrote the instructions for Population Transport minister
//       Changed - Tweaked the AI's distribution of remote unit defenses
// v1.10 Changed - Modified attack routine for lone attack ships
//       Changed - Improved AI's selection of fleet targets
//       Changed - AI repair check is now done for all ships
//       Added   - Space Yard Ships will attempt to build defense bases on warp points
//       Fixed   - Error in Fx[Ship_Order_Launch_Untis] that was preventing ships from dropping units
//       Changed - AI will check ship supplies before ordering them to attack, explore, survey, and patrol
//       Fixed   - Error that was preventing the AI from attacking enemy ships in their space
//       Fixed   - Error in Medical Ship orders
//       Changed - Renamed Fx[Medical_Ship_Orders] to Fx[Minister_Medical_Ships]
//       Changed - AI can drop troops on rioting planets
//       Changed - AI is more proactive in loading cargo on ships
//       Fixed   - Error in Fx[Does_Ship_Need_Scrapping] that prevented ships from being scrapped on occasion
//       Changed - AI Scout Ships will seek the closest system to explore or survey and will consider supply level
//       Changed - Scout and Explorer ships now handled by Minister - Survey Ships
//       Changed - Patrol Ships now handled by Minister - Patrol Ships
//       Added   - Minister - (All) Ships Cloaking
//       Added   - Added Fx[Minister_Cloaking] to control ship's use of cloaking devices and special armors
// v1.10 Added   - AI will order fleets to train at planets with Fleet Training facilities
// v1.09 Changed - Added Xenophobic race conditions to Attack Priority 3 for single ships
//       Changed - Created new locations for Fleets to hold when waiting for ships to join
//       Fixed   - Ships/Fleets were not resupplying when needed
// v1.08 Changed - Mine and Satellite Layers will now drop units at specific locations
//       Changed - Carriers will leave fleets to re-load on fighters
// v1.07 Changed - Improved AI management of fleet sizes
//       Changed - AI will clear current orders to resupply fleets
//       Added   - Support for added design types
//       Fixed   - Ships/Fleets will interrupt their existing orders to resupply
//       Fixed   - Index error in Fx[Send_Ship_To_Attack] when more ships were ordered to attack than attack/defense locations
// v1.06 Fixed   - Another error in Fx[Order_Scrap]
// v1.05 Changed - Broke up Attack Ship orders into separate functions to improve script clarity
//       Fixed   - Error in Attack Priority 2 for ships and fleets
//       Changed - AI will consider remaining resources before ordering ships to retrofit
//       Fixed   - Error in Fx[Order_Scrap]
//       Fixed   - Bombardment Ships were not receiving orders
// v1.04 Added   - Orders for Scout and Patrol Ships
//       Added   - AI will scrap obsolete ships that can no longer be upgraded
//       Fixed   - Minor error in fleet naming
// v1.03 Added   - More fleet attack priorities; removed fleet patrol locations, now used for single ships
//       Added   - Some fleet fixes from SE:V v1.25 patch
//       Changed - Adapted modified resupply check revisions from SE:V v1.25 patch
//       Added   - Enemy present function from SE:V v1.25 patch
//       Added   - Quell Riots function from SE:V 1.25 patch
// v1.02 Added   - AI will actively target enemy ships in its systems to defend
//       Added   - AI will issue various attack orders for unfleeted attack ships
//       Changed - AI won't retrofit colony ships
//       Changed - AI should not issue move orders to bases before retrofitting them
// v0.95 Changed - Updated scripts to include some SE:V AI changes for v1.09-1.13
// v0.92 Added   - Orders support for additional design types
//
// Balance Mod To-Do List:
// -----------------------
// - Investigate improvements for turn-turn ship tracking (WIP)
// - Improvements to ship escorting (v125+)
// - Improvements to AI stellar manipulation ministers (v125+)
// - Add AI capability for "Use Component" (v125+?)
// - Fully activate AI cloaking (Requires SE5 Fix)
//
// Script Function Requests:
// -------------------------
// - Sys_Get_Waypoint(plr_id, index, sys_loc, sect_loc) : boolean (Returns location of waypoint of an index 1-9)
// - Sys_Set_Waypoint(plr_id, index, sys_loc, sect_loc) : boolean (Returns TRUE if set successful)
// - Sys_Order_Space_Object_To_Cloak(sobj_id) : boolean (Returns TRUE if set successful)
// - Sys_Order_Space_Object_To_Decloak(sobj_id) : boolean (Returns TRUE if set successful)
// - Sys_Get_Fleet_Name(fleet_id) : string (Returns fleet name)
// - Sys_Set_Fleet_Name(fleet_id, fleet_name) : boolean (Returns TRUE if set successful)
// - Sys_Get_Task_Force_Name(fleet_id, tf_id) : string
// - Sys_Set_Task_Force_Name(fleet_id, tf_id, tf_name) : boolean (Returns TRUE if set successful)

//------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------
globalvars

  gbl_design_id:                       long
  gbl_SY_location:                     long
  gbl_SY_sys_loc:                      long
  gbl_SY_sect_loc:                     long
  gbl_lng_explorers_sent_out:          long
  gbl_lng_surveyors_sent_out:          long
  gbl_lng_patrols_sent_out:            long
  gbl_ship_cargo_amt_to_load:          long
  gbl_lst_sys_protected:               longlist
  gbl_lst_cargo_loc_id:                longlist
  gbl_lst_cargo_type:                  stringlist

  gbl_lst_target_loc_type:             longlist
  gbl_lst_target_index:                longlist
  gbl_lst_target_obj_id:               longlist
  gbl_lst_target_sys_loc:              longlist
  gbl_lst_target_sect_loc:             longlist

endglobalvars

//------------------------------------------------------------------------
// Forward Declarations
//------------------------------------------------------------------------
deffunc

function Load_Ship_Data returns boolean
params
end

function Save_Ship_Data returns boolean
params
end

function Minister_Attack_Bases returns boolean
params
  ship_id:                   long
end

function Minister_Attack_Ships_Normal returns boolean
params
  ship_id:                   long
end

function Minister_Patrol_Ships returns boolean
params
  ship_id:                   long
end

function Minister_Survey_Ships returns boolean
params
  ship_id:                   long
end

function Minister_Colony_Ships returns boolean
params
  ship_id:                   long
end

function Minister_Carriers_Fighter returns boolean
params
  ship_id:                   long
end

function Minister_Fighters returns boolean
params
  ship_id:                   long
end

function Minister_Drones returns boolean
params
  ship_id:                   long
end

function Minister_Troop_Transports returns boolean
params
  ship_id:                   long
end

function Minister_Population_Transports returns boolean
params
  ship_id:                   long
end

function Minister_Cargo_Transports returns boolean
params
  ship_id:                   long
end

function Minister_Satellite_Layers returns boolean
params
  ship_id:                   long
end

function Minister_Mine_Layers returns boolean
params
  ship_id:                   long
end

function Minister_SpaceYard_Ships returns boolean
params
  ship_id:                   long
end

function Minister_Attack_Ships_Boarding returns boolean
params
  ship_id:                   long
end

function Minister_Mine_Sweepers returns boolean
params
  ship_id:                   long
end

function Minister_Attack_Ships_Kamikaze returns boolean
params
  ship_id:                   long
end

function Minister_Carriers_Drone returns boolean
params
  ship_id:                   long
end

function Minister_Remote_Mining_Ships returns boolean
params
  ship_id:                   long
  design_type:               string
end

function Minister_Medical_Ships returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_OpenWarpPoint returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CloseWarpPoint returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CreatePlanet returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_DestroyPlanet returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CreateStar returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_DestroyStar returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CreateStorm returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_DestroyStorm returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CreateBlackHole returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_DestroyBlackHole returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_CreateNebulae returns boolean
params
  ship_id:                   long
end

function Minister_Stellar_DestroyNebulae returns boolean
params
  ship_id:                   long
end

function Minister_Cloaking returns boolean
params
  ship_id:                   long
end

function Minister_Naming returns boolean
params
  ship_id:                   long
end

function Minister_Mothballing returns boolean
params
  ship_id:                   long
  ship_status:               long
end

function Evaluate_Current_Orders returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Repair returns boolean
params
  ship_id:                   long
end

function Does_Ship_Need_Resupply returns boolean
params
  ship_id:                   long
end

function Does_Ship_Need_Retrofitting returns boolean
params
  ship_id:                   long
  ship_in_fleet:             boolean
end

function Order_Retrofit returns boolean
params
  ship_id:                   long
end

function Does_Ship_Need_Scrapping returns boolean
params
  ship_id:                   long
end

function Order_Scrap returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Explore returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Survey returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Attack returns boolean
params
  ship_id:                   long
  unit_group:                boolean
end

function Send_Ship_To_Patrol returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Escort returns boolean
params
  ship_id:                   long
end

function Send_Stranded_Ship_To_Roam returns boolean
params
  ship_id:                   long
end

function Send_Ship_To_Clear_Minefield returns boolean
params
  ship_id:                   long
end

function Order_Go_To_Resupply_Depot returns boolean
params
  ship_id:                   long
  fleet_id:                  long
end

function Order_Go_To_Quell_Riot returns boolean
params
  ship_id:                   long
  fleet_id:                  long
end

function Does_Fleet_Need_Design_Type returns boolean
params
  fleet_id:                  long
  fleet_type:                long
  design_type:               string
end

function Send_Ship_To_Join_Fleet returns boolean
params
  ship_id:                   long
end

function Ship_Order_Load_Cargo returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
  second_pickup:             boolean
end

function Ship_Order_Drop_Cargo returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
end

function Ship_Order_Launch_Units returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
end

function Ship_Order_Go_To_Nearest_Colony returns boolean
params
  ship_id:                   long
  curr_system_only:          boolean
end

function Ship_Order_Go_To_SY returns boolean
params
  ship_id:                   long
  clear_orders:              boolean
end

function Is_Remote_Mining_Location_Ok returns boolean
params
  ast_sys_loc:               long
  ast_sect_loc:              long
end

function Load_Fleet_Data returns boolean
params
end

function Save_Fleet_Data returns boolean
params
end

function Get_Fleet_Type_To_Add returns long
params
end

function Fleet_Orders returns boolean
params
end

function Maintain_Fleet_Task_Forces returns boolean
params
  fleet_id:                  long
end

function Maintain_Fleet_Ships returns boolean
params
  fleet_id:                  long
  fleet_index:               long
  fleet_type:                long
end

function Give_Specific_Fleet_Orders returns boolean
params
  fleet_id:                  long
  fleet_index:               long
  fleet_type:                long
end

function Get_Target_To_Attack returns long
params
  location_type:             long
  our_max_targets:           long
  our_sys_loc:               long
  our_sect_loc:              long
  our_movement:              long
  our_strength:              long
  our_obj_type:              long
  our_mine_sweep_count:      long
  our_max_atk_dist:          long
  consider_capture:          boolean
  consider_retreat:          boolean
  consider_mines:            boolean
  same_sys_only:             boolean
  single_target_only:        boolean
end

enddeffunc

//------------------------------------------------------------------------
// AI_Orders_Ships
//------------------------------------------------------------------------
function AI_Orders_Ships returns boolean
vars
  minister_controlled:       boolean
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  ship_name:                 string
  ship_status:               long
  ship_prev_status:          long
  ship_supply:               long
  ship_max_supply:           long
  ship_xp:                   real
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_armor:                long
  ship_shields:              long
  ship_structure:            long
  ship_strength:             long
  design_type:               string
  design_id:                 long
  fleet_id:                  long
  unit_group:                boolean
  orders_given:              boolean
begin

  // Note the number of explorers and surveyors
  set gbl_lng_surveyors_sent_out := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_SURVEY_SYSTEM, 0, 0, 0)
  set gbl_lng_explorers_sent_out := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_WARP, 0, 0, 0)
  set gbl_lng_patrols_sent_out := 0

  // Debug output
  call Sys_Debug_Print("Ships", "------------")
  call Sys_Debug_Print("Ships", "Ship Orders:")

  // Load our saved data
  call Load_Ship_Data()
  call Load_Fleet_Data()

  // Go through all of our ships and give them preliminary orders
  set ship_count := lst_AI_Our_Ships.count()

  if (ship_count > 0) then
    for ship_index := 1 to ship_count do
      // Get our ship's details
      set ship_id := lst_AI_Our_Ships.get(ship_index)
      set ship_name := Sys_Get_Space_Object_Name(ship_id)
      set ship_status := Sys_Get_Space_Object_Status(ship_id)

      if (lst_AI_Our_Prev_Ships.indexof(ship_id) > 0) then
        set ship_prev_status := lst_AI_Our_Prev_Ships_Status.get(lst_AI_Our_Prev_Ships.indexof(ship_id))
      else
        set ship_prev_status := 0
      endif

      set ship_xp := Sys_Get_Space_Object_Experience(ship_id)
      set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
      set ship_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
      set ship_max_supply := Sys_Get_Space_Object_Maximum_Supply(ship_id)
      set ship_armor := Sys_Get_Space_Object_Current_Armor_Structure(ship_id)
      set ship_shields := Sys_Get_Space_Object_Current_Shields(ship_id)
      set ship_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(ship_id) - ship_armor
      set ship_strength := Calculate_Space_Object_Strength(ship_id)
      set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
      set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
      set fleet_id := Sys_Get_Space_Object_Fleet(ship_id)
      set minister_controlled := Sys_Get_Space_Object_Minister_Controlled(ship_id)
      set orders_given := (Sys_Get_Space_Object_Order_Count(ship_id) > 0)

      // Is our ship really a unit group?
      if (Sys_Get_Space_Object_Type(ship_id) = SPACE_OBJECT_TYPE_UNITGROUP) then
        set unit_group := TRUE
        set design_type := Get_Unit_Group_Type(ship_id) + " Group"
      else
        set unit_group := FALSE
      endif

      // Debug output
      call Sys_Debug_Print("Ships", "  - " + ship_name + " = " + design_type)
      call Sys_Debug_Print("Ships", "    - Sobj ID = " + Sys_Convert_Long_To_String(ship_id))
      call Sys_Debug_Print("Ships", "    - Prev Status = " + Get_Status_Name(ship_prev_status))
      call Sys_Debug_Print("Ships", "    - Location = " + Sys_Get_Solar_System_Name(ship_sys_loc) + " System " + Convert_Sector_To_String(ship_sect_loc))
      call Sys_Debug_Print("Ships", "    - Supply = " + Sys_Convert_Long_To_String(ship_supply) + "/" + Sys_Convert_Long_To_String(ship_max_supply))
      call Sys_Debug_Print("Ships", "    - XP = " + Sys_Convert_Real_To_String(ship_xp))
      call Sys_Debug_Print("Ships", "    - Structure/Armor/Shields = " + Sys_Convert_Long_To_String(ship_structure) + "/" + Sys_Convert_Long_To_String(ship_armor) + "/" + Sys_Convert_Long_To_String(ship_shields))
      call Sys_Debug_Print("Ships", "    - Weapon Damage = " + Sys_Convert_Long_To_String(Sys_Get_Space_Object_Total_Weapon_Damage(ship_id)))
      call Sys_Debug_Print("Ships", "    - Calculated Strength = " + Sys_Convert_Long_To_String(ship_strength))

      // Is this a remote base?
      if (design_type = "Defense Base (S)" or design_type = "Defense Base (L)") then
        if (Get_Colony_In_Location(ship_sys_loc, ship_sect_loc) = 0) then
          // Debug output
          call Sys_Debug_Print("Ships", "    - Remote Base")
        endif
      endif

      // Is this a mothballed ship?
      if (ship_status = SHIP_STATUS_MOTHBALLED) then
        // Debug output
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Mothballing") then
          // Check to see if it should be unmothballed
          set orders_given := Minister_Mothballing(ship_id, ship_status)
        endif
      endif

      // Is our ship in a fleet?
      if (fleet_id > 0) then
        call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_FLEET)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_id))
      endif

      // Don't give orders to fleet ships, ships under construction, and mothballed ships
      if (minister_controlled) and (fleet_id = 0) and (ship_status <> SHIP_STATUS_MOTHBALLED) then

        // Debug output
        call Sys_Debug_Print("Ships", "    - Minister controlled")

        // Evaluate our ship's current orders
        if (orders_given) then
          set orders_given := Evaluate_Current_Orders(ship_id)
        endif

        // Is our ship stranded in a disconnected system?
        if (Sys_Get_System_Distance_Between_Solar_Systems(Sys_Get_Empire_Home_System(sys_long_Player_ID), ship_sys_loc) = 999) then
          set orders_given := Send_Stranded_Ship_To_Roam(ship_id)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Stranded")
        endif

        // Does our ship need to be repaired?
        if (not unit_group) and (not orders_given) then
          if (Sys_Get_Space_Object_Number_Of_Damaged_Components(ship_id) > 0) then
            if Does_Ship_Need_Repair(ship_id, 20, FALSE, FALSE, FALSE) then
              set orders_given := Send_Ship_To_Repair(ship_id)
            endif
          endif
       endif

        // Does our ship need to be resupplied?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Resupply") then
          if (not unit_group) then
            if (ship_supply * 2 < ship_max_supply) then
              if Does_Ship_Need_Resupply(ship_id) then
                set orders_given := Order_Go_To_Resupply_Depot(ship_id, 0)
               endif
            endif
          endif
        endif

        // Does our ship need to be retrofit?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Retrofit") then
          if (not orders_given) and (not unit_group) then
            if Sys_Is_Vehicle_Design_Obsolete(design_id) then
              if Does_Ship_Need_Retrofitting(ship_id, FALSE) then
                set orders_given := Order_Retrofit(ship_id)
              endif
            endif
          endif
        endif

        // Does our ship need to be scrapped?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Scrapping") then
          if (not orders_given) and (not unit_group) then
            if Does_Ship_Need_Scrapping(ship_id) then
              set orders_given := Order_Scrap(ship_id)
            endif
          endif
        endif

        // Should our ship be mothballed?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Mothballing") then
          if (not orders_given) and (not unit_group) then
            set orders_given := Minister_Mothballing(ship_id, ship_status)
          endif
        endif

        // Does our ship need to be cloaked? (Doesn't work)
        // if (not orders_given) and (not unit_group) then
        //   if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Cloaking") then
        //     call Minister_Cloaking(ship_id)
        //   endif
        // endif

        // Convert our ship's design type to a general AI design type
        set design_type := Get_General_AI_Design_Type(design_type)

        // Determine our ship's new orders based on its design type
        if (not orders_given) then

          if (design_type = "Ship (Attack)") or (design_type = "Ship (Defense)") or (design_type = "Ship (Seeker)") or (design_type = "Ship (Bombardment)") then
            if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Attack Ships") then
              call Minister_Attack_Ships_Normal(ship_id)
            endif
          endif

          case design_type
           "Ship  (Attack Base)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Attack Bases") then
               call Minister_Attack_Bases(ship_id)
             endif
           "Ship (Patrol)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Patrol Ships") then
               call Minister_Patrol_Ships(ship_id)
             endif
           "Ship (Point-Defense)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Attack Ships") then
               call Send_Ship_To_Join_Fleet(ship_id)
             endif
           "Ship (Repair)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Space Yard Ships") then
               call Minister_SpaceYard_Ships(ship_id)
             endif
           "Ship (Scout)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Survey Ships") then
               call Minister_Survey_Ships(ship_id)
             endif
           "Ship (Explorer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Survey Ships") then
               call Minister_Survey_Ships(ship_id)
             endif
           "Colonizer (Rock)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Colony Ships") then
               call Minister_Colony_Ships(ship_id)
             endif
           "Colonizer (Ice)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Colony Ships") then
               call Minister_Colony_Ships(ship_id)
             endif
           "Colonizer (Gas)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Colony Ships") then
               call Minister_Colony_Ships(ship_id)
             endif
           "Carrier (Fighter)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Fighter Carriers") then
               call Minister_Carriers_Fighter(ship_id)
             endif
           "Carrier (Drone)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Drone Carriers") then
               call Minister_Carriers_Drone(ship_id)
             endif
           "Fighter Group":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Units - Fighters") then
               call Minister_Fighters(ship_id)
             endif
           "Drone Group":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Units - Drones") then
               call Minister_Drones(ship_id)
             endif
           "Transport (Supply)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Cargo Transports") then
               call Send_Ship_To_Join_Fleet(ship_id)
             endif
           "Transport (Troop)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Troop Transports") then
               call Minister_Troop_Transports(ship_id)
             endif
           "Transport (Population)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Population Transports") then
               call Minister_Population_Transports(ship_id)
             endif
           "Transport (Cargo)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Cargo Transports") then
               call Minister_Cargo_Transports(ship_id)
             endif
           "Ship (Satellite Launcher)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Satellite Layers") then
               call Minister_Satellite_Layers(ship_id)
             endif
           "Ship (Mine Layer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Mine Layers") then
               call Minister_Mine_Layers(ship_id)
             endif
           "Ship (Space Yard)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Space Yard Ships") then
               call Minister_SpaceYard_Ships(ship_id)
             endif
           "Ship (Boarding)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Boarding Ships") then
               call Minister_Attack_Ships_Boarding(ship_id)
             endif
           "Ship (Mine Sweeper)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Mine Sweepers") then
               call Minister_Mine_Sweepers(ship_id)
             endif
           "Ship (Kamikaze)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Ramming Ships") then
               call Minister_Attack_Ships_Kamikaze(ship_id)
             endif
           "Ship (Medical)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Medical Ships") then
               call Minister_Medical_Ships(ship_id)
             endif
           "Ship (Warp Point Opener)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Warp Point Openers") then
               call Minister_Stellar_OpenWarpPoint(ship_id)
             endif
           "Ship (Warp Point Closer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Warp Point Closers") then
               call Minister_Stellar_CloseWarpPoint(ship_id)
             endif
           "Ship (Planet Creator)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Planet Creators") then
               call Minister_Stellar_CreatePlanet(ship_id)
             endif
           "Ship (Planet Destroyer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Planet Destroyers") then
               call Minister_Stellar_DestroyPlanet(ship_id)
             endif
           "Ship (Star Creator)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Star Creators") then
               call Minister_Stellar_CreateStar(ship_id)
             endif
           "Ship (Star Destroyer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Star Destroyers") then
               call Minister_Stellar_DestroyStar(ship_id)
             endif
           "Ship (Storm Creator)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Storm Creators") then
               call Minister_Stellar_CreateStorm(ship_id)
             endif
           "Ship (Storm Destroyer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Storm Destroyers") then
               call Minister_Stellar_DestroyStorm(ship_id)
             endif
           "Ship (Black Hole Creator)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Black Hole Creators") then
               call Minister_Stellar_CreateBlackHole(ship_id)
             endif
           "Ship (Black Hole Destroyer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Black Hole Destroyers") then
               call Minister_Stellar_DestroyBlackHole(ship_id)
             endif
           "Ship (Nebulae Creator)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Nebulae Creators") then
               call Minister_Stellar_CreateNebulae(ship_id)
             endif
           "Ship (Nebulae Destroyer)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Nebulae Destroyers") then
               call Minister_Stellar_DestroyNebulae(ship_id)
             endif
           "Ship (Remote Mining)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Remote Mining Ships") then
               call Minister_Remote_Mining_Ships(ship_id, design_type)
             endif
           "Ship (Remote Farming)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Remote Mining Ships") then
               call Minister_Remote_Mining_Ships(ship_id, design_type)
             endif
           "Ship (Remote Refining)":
             if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - Remote Mining Ships") then
               call Minister_Remote_Mining_Ships(ship_id, design_type)
             endif
          endcase
        endif
      endif
      // Do we have ships that need to be renamed?
      if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Naming") and (not unit_group) then
        call Minister_Naming(ship_id)
      endif
      // Debug output
      if (Sys_Get_Space_Object_Order_Count(ship_id) = 0) then
        call Sys_Debug_Print("Ships", "    - Has no orders")
      endif
    endfor
  endif

  // Give orders to our fleets
  if Sys_Using_AI_Minister(sys_long_Player_ID, "Fleets") then
    // Debug output
    call Sys_Debug_Print("Ships", "-------------")
    call Sys_Debug_Print("Ships", "Fleet Orders:")
    call Fleet_Orders()
  endif

  // Save our data
  call Save_Ship_Data()
  call Save_Fleet_Data()

  return TRUE
end

//------------------------------------------------------------------------
// Load_Ship_Data
//------------------------------------------------------------------------
function Load_Ship_Data returns boolean
vars
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  ship_status:               long
  ship_status_name:          string
  storage_index:             long
begin

  // Load our ship details from memory
  set ship_count := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 1, 9)

  // Debug output
  call Sys_Debug_Print("Ships", "    --------------------")
  call Sys_Debug_Print("Ships", "    - Loading Ship Data:")

  if (ship_Count > 0) then
    for ship_index := 1 to ship_count do
      set storage_index := (ship_index - 1) * 2
      set ship_id := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 6, storage_index + 1)
      set ship_status := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 6, storage_index + 2)
      set ship_status_name := Get_Status_Name(ship_status)
      call lst_AI_Our_Prev_Ships.add(ship_id)
      call lst_AI_Our_Prev_Ships_Status.add(ship_status)
      // Debug output
      call Sys_Debug_Print("Ships", "      - " + Sys_Get_Space_Object_Name(ship_id) + "; Status = " + ship_status_name)
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Save_Ship_Data
//------------------------------------------------------------------------
function Save_Ship_Data returns boolean
vars
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  ship_status:               long
  ship_status_name:          string
  storage_index:             long
begin

  // Save our ship data to memory
  set ship_count := lst_AI_Our_Ships.count()
  call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 1, 9, ship_count)

  // Debug output
  call Sys_Debug_Print("Ships", "---------------------")
  call Sys_Debug_Print("Ships", "  - Saving Ship Data:")

  if (ship_Count > 0) then
    for ship_index := 1 to ship_count do
      set storage_index := (ship_index - 1) * 2
      set ship_id := lst_AI_Our_Ships.get(ship_index)
      set ship_status := lst_AI_our_Ships_Status.get(ship_index)
      set ship_status_name := Get_Status_Name(ship_status)
      // Save our ship's details
      call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 6, storage_index + 1, ship_id)
      call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 6, storage_index + 2, ship_status)
      // Debug output
      call Sys_Debug_Print("Ships", "    - " + Sys_Get_Space_Object_Name(ship_id) + "; Status = " + ship_status_name)
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Minister_Attack_Bases
//------------------------------------------------------------------------
function Minister_Attack_Bases returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Is there a target for our Base Ship to attack?
  set orders_given := Send_Ship_To_Attack(ship_id, FALSE)

  // If no orders, send our Attack Base to join a fleet
  if (not orders_given) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Attack_Ships_Boarding
//------------------------------------------------------------------------
function Minister_Attack_Ships_Boarding returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Send our Boarding Ships to join fleets
  if (not orders_given) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Attack_Ships_Normal
//------------------------------------------------------------------------
function Minister_Attack_Ships_Normal returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  design_type:               string
begin

  // Convert our ship's design type to its general type
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set design_type := Get_General_AI_Design_Type(design_type)

  // Priority 1 - Are there targets for our ship to attack?
  set orders_given := Send_Ship_To_Attack(ship_id, FALSE)

  // Priority 2 - Some design types are always sent to fleets
  if (design_type = "Ship (Defense)") or (design_type = "Ship (Seeker)") or (design_type = "Ship (Point-Defense)") or (design_type = "Ship (Repair)") then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  // Priority 3 - Are there ships that need to be escorted?
  if (not orders_given) then
    set orders_given := Send_Ship_To_Escort(ship_id)
  endif

  // Priority 4 - Clear marked minefields with zero mines
  if (not orders_given) then
    set orders_given := Send_Ship_To_Clear_Minefield(ship_id)
  endif

  // Priority 5 - If no orders, see if our ship can be sent to survey or explore
  if (not orders_given) and (Sys_Get_Random_Long(1, 2) = 1) then
    set orders_given := Send_Ship_To_Survey(ship_id)
  endif
  if (not orders_given) and (Sys_Get_Random_Long(1, 2) = 1) then
    set orders_given := Send_Ship_To_Explore(ship_id)
  endif

  // If no orders, send our ship to join a fleet
  if (not orders_given) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Attack_Ships_Kamikaze
//------------------------------------------------------------------------
function Minister_Attack_Ships_Kamikaze returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Send all our Kamikaze Attack Ships to join fleets
  set orders_given := Send_Ship_To_Join_Fleet(ship_id)

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Survey_Ships
//------------------------------------------------------------------------
function Minister_Survey_Ships returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  skip_explore:              boolean := FALSE
  design_type:               string
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Make sure our ship has working basic sensors
  if Is_Component_Damaged(ship_id, "Basic Sensors") then
    call Sys_Space_Object_Clear_Orders(ship_id)
    // Order it to repair
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  // Are we already in a system we can survey?
  if (lst_AI_Survey_System.indexof(ship_sys_loc) > 0) then
    set skip_explore := TRUE
  endif

  // Priority 1 - Send our ship to explore
  if (not orders_given) and (lst_AI_Explore_System.count() > 0) and (not skip_explore) then
    set orders_given := Send_Ship_To_Explore(ship_id)
  endif

  // Priority 1a - Considering attack sometimes for Scout Ships
  if (not orders_given) and (bool_Race_Is_Not_Alone) and (design_type = "Ship (Scout)") then
    set orders_given := Send_Ship_To_Attack(ship_id, FALSE)
  endif

  // Priority 2 - Send our ship to survey
  if (not orders_given) then
    set orders_given := Send_Ship_To_Survey(ship_id)
  endif

  // Priority 3 - Clear marked minefields with zero mines
  if (not orders_given) then
    set orders_given := Send_Ship_To_Clear_Minefield(ship_id)
  endif

  // Priority 4 - Send our ship to patrol
  if (not orders_given) then
    set orders_given := Send_Ship_To_Patrol(ship_id)
  endif

  // If no orders, send our ship to the nearest colony
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Patrol_Ships
//------------------------------------------------------------------------
function Minister_Patrol_Ships returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Priority 1 - Is there a target for our ship to attack?
  set orders_given := Send_Ship_To_Attack(ship_id, FALSE)

  // Priority 2 - Do we have ships to escort?
  if (not orders_given) then
    set orders_given := Send_Ship_To_Escort(ship_id)
  endif

  // Priority 3 - Send our Patrol Ship to patrol
  if (not orders_given) then
    set orders_given := Send_Ship_To_Patrol(ship_id)
  endif

  // Priority 4 - Clear marked minefields with zero mines
  if (not orders_given) then
    set orders_given := Send_Ship_To_Clear_Minefield(ship_id)
  endif

  // If no orders, send our ship to the nearest colony
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Carriers_Fighter
//------------------------------------------------------------------------
function Minister_Carriers_Fighter returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Does our Carrier need to load fighters?
  if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter", 75) then
    set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter", FALSE)
  endif

  // Send our Carrier to a fleet if it has a load of fighters
  if (not orders_given) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  // If no orders, send our ship to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Carriers_Drone
//------------------------------------------------------------------------
function Minister_Carriers_Drone returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Does our Drone Carrier need to load drones?
  if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Drone", 75) then
    set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Drone", FALSE)
  endif

  // Send our Drone Carrier to a fleet if it has a load of drones
  if (not orders_given) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  // If no orders, send our ship to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Fighters
//------------------------------------------------------------------------
function Minister_Fighters returns boolean
params
  ship_id:                   long
vars
  ship_movement:             long
  ship_sys_loc:              long
  ship_sect_loc:             long
  orders_given:              boolean := FALSE
begin

  // Get our Fighter group's location
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Is there a nearby Space Yard or Colony we can order our Fighter group to go to?
  if (ship_movement > 0) then
    // Are there targets for our Fighter group to attack?
    set orders_given := Send_Ship_To_Attack(ship_id, TRUE)
    // If no orders, go to our nearest colony in the system
    if (not orders_given) then
      if (Get_A_Colony_Location_In_System(ship_sys_loc) > 0) then
        // If no orders, send our Fighter group to the nearest colony
        set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, TRUE)
      endif
    endif
  endif

  // If no orders, Fighter Group is stranded and should be destroyed
  if (not orders_given) then
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_SELF_DESTRUCT, ship_sys_loc, ship_sect_loc, 0)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Scrapped")
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Drones
//------------------------------------------------------------------------
function Minister_Drones returns boolean
params
  ship_id:                   long
vars
  ship_movement:             long
  ship_sys_loc:              long
  ship_sect_loc:             long
  orders_given:              boolean := FALSE
begin

  // Get our Drone group's location
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Is there a nearby Space Yard or Colony we can order our Drone group to go to?
  if (ship_movement > 0) then
    // Are there targets for our Drone group to attack?
    if (not orders_given) then
      set orders_given := Send_Ship_To_Attack(ship_id, TRUE)
    endif
    if (not orders_given) then
      if (Get_A_Colony_Location_In_System(ship_sys_loc) > 0) then
        // If no orders, send our Drone group to the nearest colony
        set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
      endif
    endif
  endif

  // If no orders, Drone Group is stranded and should be destroyed
  if (not orders_given) then
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_SELF_DESTRUCT, ship_sys_loc, ship_sect_loc, 0)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Drone group scrapped")
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Troop_Transports
//------------------------------------------------------------------------
function Minister_Troop_Transports returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Does our Troop Transport need to load troops?
  if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Troop", 50) then
    if (Sys_Get_Random_Long(1, 5) = 1) then
      // Consider loading fighters on occasion
      set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter", FALSE)
    else
      set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Troop", FALSE)
     endif
  endif

  // Send our Troop Transport to stop a riot or join a fleet if it has a load of troops
  if (not orders_given) then
    if (lst_AI_Our_Rioting_Colonies.count() > 0) then
      set orders_given := Order_Go_To_Quell_Riot(ship_id, 0)
    else
      set orders_given := Send_Ship_To_Join_Fleet(ship_id)
    endif
  endif

  // If no orders, send our ship to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Colony_Ships
//------------------------------------------------------------------------
function Minister_Colony_Ships returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  design_type:               string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_movement:             long
  list_count:                long
  list_index:                long
  planet_id:                 long
  planet_sys_loc:            long
  planet_sect_loc:           long
  planet_dist:               long
  planet_size:               long
  planet_name:               string
  target_planet_id:          long
  target_planet_dist:        long
  target_index:              long
  target_dangerous:          boolean := FALSE
  colony_sys_loc:            long
  colony_sect_loc:           long
  colony_id:                 long
  colony_dist:               long
  colony_pop:                long
  move_sys_loc:              long
  move_sect_loc:             long
  move_planet_id:            long
  this_value:                long
  min_value:                 long := -999999
  this_dist:                 long
  min_dist:                  long := 999999
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Find a planet for our ship to colonize from our list of planets to colonize
  set list_count := lst_AI_Planets_To_Colonize.count()

  // Search for a planet that can be colonized
  if (list_count > 0) then
    for list_index := 1 to list_count do
      set planet_id := lst_AI_Planets_To_Colonize.get(list_index)

      // Can we colonize this type of planet?
      if Sys_Can_Space_Object_Colonize_Planet(ship_id, planet_id) then
        set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
        set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
        set planet_size := Get_Planet_Size(planet_id)
        set planet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
        // Are we the closest Colonizer to the target?
        if (planet_dist <= Find_Nearest_Ship_Distance_To_Location(planet_sys_loc, planet_sect_loc, TRUE, design_type, TRUE)) then
          // Can we colonize in this system?
          if Can_System_Be_Colonized(planet_sys_loc) then
            // Determine colonization value
            set this_value := planet_size * 5
            // Is it breathable?
            if Sys_Is_Planet_Breathable(planet_id, sys_long_Player_ID) then
              set this_value := this_value * 2
            endif
            // Is it far?
            set this_value := this_value - planet_dist
          else
            set this_value := -999999
          endif
          // Determine the best planet for this ship to colonize
          if (this_value > min_value) and (planet_dist < 100) then
            set min_value := this_value
            set target_index := list_index
            set target_planet_id := planet_id
            set target_planet_dist := planet_dist
          endif
        endif
      endif
    endfor
  endif

  // Order our colony ship to colonize the planet
  if (target_planet_id > 0) then
    set planet_sys_loc := Sys_Get_Space_Object_System_Location(target_planet_id)
    set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(target_planet_id)

    // Do we need to protect the target planet?
    if Is_Enemy_Present_In_System(planet_sys_loc) or Is_Enemy_Present_In_Adjacent_Systems(planet_sys_loc) then
      set target_dangerous := TRUE
    endif

    // Have our Colony Ship pick up population from the nearest colony
    set list_count := lst_AI_Our_Colonies.count()

    if (list_count > 0) then
      set this_value := 0
      set min_value := 100
      // Pick a nearby colony to pick up population from
      for list_index := 1 to list_count do
        set colony_id := lst_AI_Our_Colonies.get(list_index)
        set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
        set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
        // Make sure our enemies are not at the location
        if (not Is_Enemy_Present_In_Sector(colony_sys_loc, colony_sect_loc)) then
          set colony_pop := Sys_Get_Planet_Population(colony_id)
          set colony_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, colony_sys_loc, colony_sect_loc)
          set this_value := colony_pop - (colony_dist * 100)
            // Choose a populated nearby planet
            if (this_value > min_value) and (colony_dist <= 10) then
              set min_value := this_value
              set move_sys_loc := colony_sys_loc
              set move_sect_loc := colony_sect_loc
              set move_planet_id := colony_id
            endif
        endif
      endfor
    endif

    if (target_dangerous) then
      // Load defensive units if available to provide basic defense for a target planet in a potentially dangerous area
      call Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
      call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Mine", move_planet_id)
      call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter", move_planet_id)
      call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Satellite", move_planet_id)
      call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Weapon Platform", move_planet_id)
      // Attempt to fill any remaining space with population
      call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_POPULATION, "", move_planet_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to pick up units before colonization")
    else
      // Only load population
      if (Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_POPULATION, "") = 0) then
        call Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
        call Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, CARGO_ITEM_TYPE_POPULATION, "", move_planet_id)
      endif
    endif

    // Order our ship to colonize the planet
    call Sys_Give_Space_Object_Order_Moveto(ship_id, planet_sys_loc, planet_sect_loc)
    call Sys_Give_Space_Object_Order_Colonize(ship_id, target_planet_id)
    call lst_AI_Planets_To_Colonize.delete(target_index)
    // Note if we will colonize the planet this turn
    if (target_planet_dist < ship_movement - 1) then
      set lng_Num_Planets_Colonized_This_Turn := lng_Num_Planets_Colonized_This_Turn + 1
    endif
    // Debug output
    set planet_name := Sys_Get_Space_Object_Name(target_planet_id)
    call Sys_Debug_Print("Ships", "    - Ordered to colonize " + planet_name + " (" + Sys_Convert_Long_To_String(target_planet_dist) + ")")
    set orders_given := TRUE
  endif

  // If no orders, use our Colony Ship for transporting population
  if (not orders_given) then
    if (lst_AI_Our_Colonies.count() > 1) then
      call Minister_Population_Transports(ship_id)
    else
      call Send_Ship_To_Explore(ship_id)
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Population_Transports
//------------------------------------------------------------------------
function Minister_Population_Transports returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_cargo_space:          long
  ship_has_cargo:            boolean := FALSE
  ship_movement:             long
  ship_movement_left:        long
  list_count:                long
  list_index:                long
  cargo_count:               long
  cargo_index:               long
  planet_id:                 long
  planet_name:               string
  planet_index:              long
  planet_pop:                long
  planet_pop_id:             long
  planet_pop_atmosphere:     string
  planet_pop_pct:            long
  planet_pop_open:           long
  planet_size:               long
  planet_sys_loc:            long
  planet_sect_loc:           long
  planet_dist:               long
  cargo_pop_id:              long
  cargo_pop_amount:          long
  cargo_pop_atmosphere:      string
  planet_atmosphere:         string
  this_value:                long
  min_value:                 long := 999999
  max_value:                 long := -999999
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_cargo_space := Sys_Get_Space_Object_Cargo_Space_Remaining(ship_id)
  set ship_has_cargo := Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)

  // If our ship already has cargo, check the population's preferred atmosphere
  if (ship_has_cargo) then
    set cargo_pop_id := Get_Population_ID(ship_id)
    call Sys_Debug_Print("Ships", "    - Population cargo item ID = " + Sys_Convert_Long_To_String(cargo_pop_id))
    set cargo_pop_atmosphere := Sys_Get_Space_Object_Cargo_Item_Population_Atmosphere_Breathed(ship_id, cargo_pop_id)
    set cargo_pop_amount := Sys_Get_Space_Object_Cargo_Item_Space_Used(ship_id, cargo_pop_id)
    set cargo_pop_amount := Sys_Divide_Long(cargo_pop_amount, 50)
    // Debug output
    if (cargo_pop_amount > 0) then
      call Sys_Debug_Print("Ships", "    - Carrying " + Sys_Convert_Long_To_String(cargo_pop_amount) + "M population (" + cargo_pop_atmosphere +")")
    endif

    // Determine a nearby lowly populated planet for our ship to drop its population
    if (cargo_pop_id > 0) then
      set list_count := lst_AI_Our_Colonies.count()
      // Go through our colonies
      if (list_count > 0) then
        for list_index := 1 to list_count do
          set planet_id := lst_AI_Our_Colonies.get(list_index)
          set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
          set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
          set planet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
          set planet_size := Get_Planet_Size(planet_id)
          set planet_pop := Sys_Get_Planet_Population(planet_id)
          set planet_pop_pct := Get_Planet_Population_Pct(planet_id)
          set planet_pop_open := Get_Planet_Population_Space_Available(planet_id)
          set planet_atmosphere := Get_Planet_Atmosphere_Type_Name(Sys_Get_Planet_Atmosphere_Type(planet_id))
          set this_value := planet_pop_pct + planet_dist
          // Prioritize our planets with 0 population regardless of distance!
          if (lst_AI_Our_Zero_Population_Colonies.indexof(planet_id) > 0) then
            set this_value := -999999
          endif
          // Adjustment to prioritize colonies at less than 50M
          if (planet_pop >= 50) then
            set this_value := this_value + 500
          endif
          // Don't try to drop on planets that are full!
          if (planet_pop_open > cargo_pop_amount) then
            set this_value := this_value - (10 * (100 - planet_pop_pct))
          else
            set this_value := 999999
          endif
          // Don't add a non-breathing population to our breathable planets
          if (cargo_pop_atmosphere <> planet_atmosphere) and (planet_pop_open > 0) then
            // Penalize domed planets to promote breathable planets unless no other choices exist
            if Sys_Is_Planet_Domed(planet_id) then
              set this_value := this_value + 1000
            else
              set this_value := 999999
            endif
          endif
          // Don't drop population at our planets with transport ships in transit already
          if (Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_MOVETO, planet_sys_loc, planet_sect_loc, planet_id) > 0) or (Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_DROP, planet_sys_loc, planet_sect_loc, planet_id) > 0) or (lst_AI_Our_Colonies_Receiving_Population.indexof(planet_id) > 0) then
            set this_value := 999999
          endif
          // Debug output
          call Sys_Debug_Print("Ships", "      - " + Sys_Get_Space_Object_Name(planet_id) + " (" + planet_atmosphere + ") population = " + Sys_Convert_Long_To_String(planet_pop) + "M; Space = " + Sys_Convert_Long_To_String(planet_pop_open) + "M; Destination value = " + Sys_Convert_Long_To_String(this_value))
          // Is this the best planet for our ship to take population to?
          if (this_value < min_value) then
            set min_value := this_value
            set planet_index := list_index
          endif
        endfor
      endif
    endif
    // Order our ship to move to the selected planet and drop its population
    if (planet_index > 0) then
      set planet_id := lst_AI_Our_Colonies.get(planet_index)
      set planet_name := Sys_Get_Space_Object_name(planet_id)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
      set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      set planet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
      // Give our ship the order to drop population
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, planet_sys_loc, planet_sect_loc)
      set orders_given := Sys_Give_Space_Object_Order_Drop_All_Cargo(ship_id, CARGO_ITEM_TYPE_POPULATION, "", planet_id)
      // Update our list of colonies due population
      call lst_AI_Our_Colonies_Receiving_Population.add(planet_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to drop population at " + planet_name + " with room for " + Sys_Convert_Long_To_String(planet_pop_open) + "M population")
      // Check for leftover movement
      if (ship_movement > 0) and (planet_dist > 0) then
        set ship_movement_left := Sys_Mod_Long(planet_dist, ship_movement)
        // Debug output
        call Sys_Debug_Print("Ships", "      - Has " + Sys_Convert_Long_To_String(ship_movement_left) + " movement left after drop")
      endif
    endif
  endif

  // Determine a nearby highly populated planet for our ship to pick up population
  if (not ship_has_cargo) or (ship_movement_left > 0) then
    set list_count := lst_AI_Our_Colonies.count()

    if (list_count > 0) then
      for list_index := 1 to list_count do
        set planet_id := lst_AI_Our_Colonies.get(list_index)
        set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
        set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
        set planet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
        set planet_pop := Sys_Get_Planet_Population(planet_id)
        set planet_pop_pct := Get_Planet_Population_Pct(planet_id)
        // Choose from only planets with more than 300M population
        if (planet_pop > 300) then
          set this_value := planet_pop_pct - planet_dist
        else
          set this_value := -999999
        endif
        // Choose the best planet as a factor of distance and the planet's relative population fill
        if (this_value > max_value) then
          set max_value := this_value
          set planet_index := list_index
        endif
      endfor
    endif

    // Order our ship to pick up the population
    if (planet_index > 0) then
      set planet_id := lst_AI_Our_Colonies.get(planet_index)
      set planet_name := Sys_Get_Space_Object_name(planet_id)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
      set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      set planet_pop_id := Get_Population_ID(planet_id)
      set planet_pop_atmosphere := Sys_Get_Space_Object_Cargo_Item_Population_Atmosphere_Breathed(planet_id, planet_pop_id)
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, planet_sys_loc, planet_sect_loc)
      set cargo_pop_amount := Sys_Divide_Long(ship_cargo_space, 50)
      // Pick up as much population as we can
      set cargo_count := Sys_Divide_Long(ship_cargo_space, 50)
      if (cargo_count > 0) then
        for cargo_index := 1 to cargo_count do
          set orders_given := Sys_Give_Space_Object_Order_Load_Specific_Cargo(ship_id, planet_pop_id, planet_id)
        endfor
      endif
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to pick up population (" + planet_pop_atmosphere + ") from " + planet_name + "; Cargo capacity = " + Sys_Convert_Long_To_String(cargo_pop_amount) + "M population")
    endif
  endif

  // If no orders send our Population Transport to the nearest colony
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Cargo_Transports
//------------------------------------------------------------------------
function Minister_Cargo_Transports returns boolean
params
  ship_id:                   long
vars
  unit_type:                 string
  ship_has_cargo:            boolean := FALSE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_has_cargo := Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id)

  // If we have a colonies with no population, hijack our Cargo Transport for use as a Population Transport
  if (lst_AI_Our_Zero_Population_Colonies.count() > 0) and (not ship_has_cargo) then
    set orders_given := Minister_Population_Transports(ship_id)
  endif

  if (not orders_given) and (ship_has_cargo) then
    // Which unit are we carrying most of?
    set unit_type := What_Unit_Type_Is_Our_Main_Cargo(ship_id)
  endif

  if (not orders_given) then
    if (unit_type <> "") then
      // Does our cargo transport need to pick up more of the unit?
      if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, unit_type, 50) then
        set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, unit_type, FALSE)
      endif
    else
      // Pick a unit type to pickup
      case Sys_Get_Random_Long(1, 2)
        1:
          set unit_type := "Fighter"
        2:
          set unit_type := "Weapon Platform"
      endcase
      // Order our cargo transport to load the cargo
      set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, unit_type, FALSE)
    endif
  endif

  // Order the cargo to be dropped
  if (not orders_given) and (ship_has_cargo) then
    set orders_given := Ship_Order_Drop_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, unit_type)
  endif

  // If no orders, go to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Satellite_Layers
//------------------------------------------------------------------------
function Minister_Satellite_Layers returns boolean
params
  ship_id:                   long
vars
  ship_has_cargo:            boolean := FALSE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_has_cargo := Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id)

  // Does our Satellite Launcher need to load satellites?
  if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Satellite", 75) then
    set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Satellite", FALSE)
  endif

  // If our Satellite Launcher has satellites in cargo then order our ship to launch them
  if (not orders_given) and (ship_has_cargo) then
    set orders_given := Ship_Order_Launch_Units(ship_id, CARGO_ITEM_TYPE_UNIT, "Satellite")
  endif

  // If no orders, go to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Mine_Layers
//------------------------------------------------------------------------
function Minister_Mine_Layers returns boolean
params
  ship_id:                   long
vars
  ship_has_cargo:            boolean := FALSE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_has_cargo := Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id)

  // Does our Mine Layer need to load mines?
  if Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Mine", 75) then
    set orders_given := Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Mine", FALSE)
  endif

  // If our Mine Layer has mines in cargo then order our ship to launch them
  if (not orders_given) and (ship_has_cargo) then
    set orders_given := Ship_Order_Launch_Units(ship_id, CARGO_ITEM_TYPE_UNIT, "Mine")
  endif

  // If no orders, go to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_SpaceYard_Ships
//------------------------------------------------------------------------
function Minister_SpaceYard_Ships returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  design_type:               string
  list_count:                long
  list_index:                long
  list_position:             long
  dmg_ship_id:               long
  dest_sys_loc:              long
  dest_sect_loc:             long
  dest_dist:                 long
  move_sys_loc:              long
  move_sect_loc:             long
  num_bases:                 long
  base_design_id:            long
  location_priority:         long
  location_strength:         long
  location_pts:              long
  min_location_pts:          long := 999999
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Is our ship's Space Yard functional?
  if Is_Component_Damaged(ship_id, "Space Yard") then
    call Sys_Space_Object_Clear_Orders(ship_id)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Space Yard Damaged")
    // Order it to repair
    set orders_given := Send_Ship_To_Repair(ship_id)
  endif

  // Is our Space Yard Ship building anything?
  if (Sys_Get_Construction_Queue_Item_Count(ship_id) > 0) then
    set orders_given := TRUE
    // Debug output
    call Sys_Debug_Print("Ships", "    - Constructing item in " + Sys_Get_Solar_System_Name(ship_sys_loc) + " System " + Convert_Sector_To_String(ship_sect_loc))
  endif

  // Priority 1 - Help repair stacks of repairing ships
  if (not orders_given) then
    set list_count := lst_AI_Repair_Location_System.count()

    if (list_count > 0) then
      set min_location_pts := 100
      // Go to the nearest repairing stack of ships
      for list_index := 1 to list_count do
        set dest_sys_loc := lst_AI_Repair_Location_System.get(list_index)
        set dest_sect_loc := lst_AI_Repair_Location_Sector.get(list_index)
        set dest_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, dest_sys_loc, dest_sect_loc)
        set location_strength := lst_AI_Repair_Location_Repair_Tonnage.get(list_index)
        set location_pts := (dest_dist * 100 - location_strength)
        // Is it a low repair priority stack or Do we already have a Space Yard shop moving to that location?
        if (location_strength < 1000) or (dest_dist > 50) or Does_Another_Ship_Have_Same_Order(ship_id, ORDER_MOVETO, TRUE, dest_sys_loc, dest_sect_loc, FALSE, 0, TRUE, "Space Yard Ship") then
          set location_pts := 999999
        endif
        // Find the best suited repair stack
        if (location_pts < min_location_pts) then
          set min_location_pts := location_pts
          set move_sys_loc := dest_sys_loc
          set move_sect_loc := dest_sect_loc
          set list_position := list_index
        endif
      endfor
      // Order our ship to the repair stack
      if (move_sys_loc > 0) then
        set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Assist with repairs in " + Sys_Get_Solar_System_Name(move_sys_loc) + " System " + Convert_Sector_To_String(move_sect_loc))
      endif
    endif
  endif

  // Priority 2 - Repair our nearest stranded ship
  if (not orders_given) then
    set list_count := lst_AI_Our_Disabled_Ships.count()
    // Find a damaged ship to rescue
    if (list_count > 0) then
      set dmg_ship_id :=  Find_Nearest_Object_In_List(lst_AI_Our_Disabled_Ships, ship_sys_loc, ship_sect_loc, TRUE, FALSE)
      set dest_sys_loc := Sys_Get_Space_Object_System_Location(dmg_ship_id)
      set dest_sect_loc := Sys_Get_Space_Object_Sector_Location(dmg_ship_id)
      // Order our Space Yard Ship to the stranded ship's location
      if (dest_sys_loc > 0) then
        set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, dest_sys_loc, dest_sect_loc)
        call lst_AI_Our_Disabled_Ships.delete(lst_AI_Our_Disabled_Ships.indexof(dmg_ship_id))
        // Debug output
        call Sys_Debug_Print("Ships", "    - Repair stranded " + Sys_Get_Space_Object_Name(dmg_ship_id) + " in " + Sys_Get_Solar_System_Name(dest_sys_loc) + " System " + Convert_Sector_To_String(dest_sect_loc))
      endif
    endif
  endif

  // Priority 3 - Build remote Defense Bases
  if (not orders_given) then
    if (design_type = "Ship (Space Yard)") then
      // Do we have a current Defense Base design?
      if (lng_Pct_Large_Bases > 0) and (Sys_Get_Random_Long(1, 100) <= lng_Pct_Large_Bases) then
        set base_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, "Base (Defense L)")
      else
        set base_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, "Base (Defense S)")
      endif
      // Find a location to build the remote defense base
      if (base_design_id) then
        set list_count := lst_AI_Remote_Base_Location_System.count()
        // Choose the highest priority, closest to our ship, and least defended location
        for list_index := 1 to list_count do
          set dest_sys_loc := lst_AI_Remote_Base_Location_System.get(list_index)
          set dest_sect_loc := lst_AI_Remote_Base_Location_Sector.get(list_index)
          set dest_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, dest_sys_loc, dest_sect_loc)
          set location_priority := Sys_Max_Long(lst_AI_Remote_Base_Location_Priority.get(list_index), 1)
          set location_strength := Calculate_Sector_Strength(dest_sys_loc, dest_sect_loc, TRUE, FALSE, FALSE)
          set location_pts := Sys_Trunc((dest_dist * 10 + location_strength) / location_priority)
          // Do we already have a Space Yard moving to or present at that location?
          if Does_Another_Ship_Have_Same_Order(ship_id, ORDER_MOVETO, TRUE, dest_sys_loc, dest_sect_loc, FALSE, 0, TRUE, "Ship (Space Yard)") or Is_Another_Ship_At_Location(ship_id, dest_sys_loc, dest_sect_loc, TRUE, "Ship (Space Yard)") then
            set location_pts := 999999
          endif
          // Find the best location to build a remote Defense Base
          if (location_pts < min_location_pts) then
            set min_location_pts := location_pts
            set move_sys_loc := dest_sys_loc
            set move_sect_loc := dest_sect_loc
            set list_position := list_index
          endif
        endfor
        // Has our ship arrived a base construction location?
        if (ship_sys_loc = move_sys_loc) and (ship_sect_loc = move_sect_loc) then
          set orders_given := Sys_Add_Vehicle_Design_To_Construction_Queue(ship_id, base_design_id, 1)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Construct remote base in " + Sys_Get_Solar_System_Name(move_sys_loc) + " System " + Convert_Sector_To_String(move_sect_loc))
        endif
        // Order our Space Yard Ship to go to a suitable location for construction of a defense base
        if (move_sys_loc > 0) and (not orders_given) then
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Move to " + Sys_Get_Solar_System_Name(move_sys_loc) + " System " + Convert_Sector_To_String(move_sect_loc) + " to construct remote base")
        endif
      endif
    endif
  endif

  // Send our Repair Ships to join fleets if they are not doing anything else
  if (not orders_given) and (design_type = "Ship (Repair)") then
    call Send_Ship_To_Join_Fleet(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Mine_Sweepers
//------------------------------------------------------------------------
function Minister_Mine_Sweepers returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_mine_sweep_count:     long
  list_count:                long
  list_index:                long
  lst_sys:                   longlist
  lst_sect:                  longlist
  found_sys_loc:             long := 0
  found_sect_loc:            long := 0
  found_index:               long
  marked_sys_loc:            long
  marked_sect_loc:           long
  marked_mine_count:         long
  min_dist:                  long := 999999
  this_dist:                 long
  ship_solitary_minesweeper: boolean
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_mine_sweep_count := Get_Mine_Sweep_Count(ship_id)
  set ship_solitary_minesweeper := (lst_AI_Solitary_Minesweepers.indexof(ship_id) > 0)

  // Check our marked minefields for ones that can be swept
  set list_count := lst_AI_Marked_Minefield_Sys.count()

  // Find the nearest marked minefield
  if (ship_solitary_minesweeper) then
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set marked_sys_loc := lst_AI_Marked_Minefield_Sys.get(list_index)
        set marked_sect_loc := lst_AI_Marked_Minefield_Sect.get(list_index)
        set marked_mine_count := lst_AI_Marked_Minefield_Count.get(list_index)
        set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, marked_sys_loc, marked_sect_loc)
        // Only consider marked minefields in systems with colonies
        if (marked_mine_count > 0) and (marked_mine_count <= ship_mine_sweep_count) then
          if (lst_AI_Our_Colony_Systems.indexof(marked_sys_loc) > 0) then
            set min_dist := this_dist
            set found_sys_loc := marked_sys_loc
            set found_sect_loc := marked_sect_loc
            set found_index := list_index
          endif
        endif
      endfor
    endif
    // Order our ship to clear the mines at the chosen location
    if (found_sys_loc > 0) then
      set orders_given := Sys_Give_Space_Object_Order_MoveTo(ship_id, found_sys_loc, found_sect_loc)
      // Remove the marked minefield location
      call lst_AI_Marked_Minefield_Sys.delete(found_index)
      call lst_AI_Marked_Minefield_Sect.delete(found_index)
      call lst_AI_Marked_Minefield_Count.delete(found_index)
      // Debug output
      call Sys_Debug_print("Ships", "    - Ordered to sweep mines in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
    endif
  endif

  // If no orders, send our Mine Sweeper to a fleet
  if (not orders_given) and (not ship_solitary_minesweeper) then
    set orders_given := Send_Ship_To_Join_Fleet(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Is_Remote_Mining_Location_Ok
//------------------------------------------------------------------------
function Is_Remote_Mining_Location_Ok returns boolean
params
  ast_sys_loc:               long
  ast_sect_loc:              long
vars
  sobj_list:                 longlist
  num_sobj:                  long
  ships_enroute:             long
  location_ok:               boolean := TRUE
begin

  // Determine if the selected asteroid field is good for remote resource gathering
  set num_sobj := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(sys_long_Player_ID, SPACE_OBJECT_TYPE_SHIP, ast_sys_loc, ast_sect_loc, sobj_list)
  set ships_enroute := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_MOVETO, ast_sys_loc, ast_sect_loc, 0)

  // Are there ships already there?
  if (num_sobj > 0) then
    set location_ok := FALSE
  endif
  // Check for ships that may be in transit
  if (ships_enroute > 0) then
    set location_ok := FALSE
  endif
  // Is the asteroid field in one of our systems to avoid?
  if (lst_AI_System_To_Avoid.indexof(ast_sys_loc) > 0) then
    set location_ok := FALSE
  endif

  return location_ok
end

//------------------------------------------------------------------------
// Minister_Remote_Mining_Ships
//------------------------------------------------------------------------
function Minister_Remote_Mining_Ships returns boolean
params
  ship_id:                   long
  design_type:               string
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  ast_id:                    long
  ast_sys_loc:               long
  ast_sect_loc:              long
  ast_value:                 resources
  ast_minerals:              real
  ast_organics:              real
  ast_radioactives:          real
  sobj_list:                 longlist
  num_asteroids:             long
  num_ships:                 long
  list_count:                long
  list_index:                long
  this_dist:                 long
  min_dist:                  long := 999999
  dist_mod:                  long
  move_sys_loc:              long
  move_sect_loc:             long
  sys_name:                  string
begin

  // Get our ship's location
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Are we already in an asteroid field gathering resources?
  set num_asteroids := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(sys_long_Player_ID, SPACE_OBJECT_TYPE_ASTEROIDS, ship_sys_loc, ship_sect_loc, sobj_list)

  if (num_asteroids >= 1) then
    set num_ships := Sys_Get_List_Of_Visible_Space_Objects_In_Sector(sys_long_Player_ID, SPACE_OBJECT_TYPE_SHIP, ship_sys_loc, ship_sect_loc, sobj_list)
    // Are we the only ship there?
    if (num_ships <= 1) then
      set orders_given := TRUE
      set sys_name := Sys_Get_Solar_System_Name(ship_sys_loc)
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_REMOTE_MINE)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Remotely gathering resources in " + sys_name + " system at sector " + Convert_Sector_To_String(ship_sect_loc))
    else
      set orders_given := FALSE
    endif
  endif

  // Find a nearby asteroid field to gather resources remotely
  if (not orders_given) then
    set list_count := lst_AI_Asteroid_Fields_For_Resources.count()
    // Find the nearest suitable asteroid field
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set ast_id := lst_AI_Asteroid_Fields_For_Resources.get(list_index)
        set ast_sys_loc := Sys_Get_Space_Object_System_Location(ast_id)
        set ast_sect_loc := Sys_Get_Space_Object_Sector_Location(ast_id)
        set ast_value := Sys_Get_Space_Object_Planet_Value(ast_id)
        set ast_minerals := ast_value.get(RESOURCE_TYPE_MINERALS)
        set ast_organics := ast_value.get(RESOURCE_TYPE_ORGANICS)
        set ast_radioactives := ast_value.get(RESOURCE_TYPE_RADIOACTIVES)

        // For finite resource games
        if Sys_Is_Finite_Resource_Game() then
          // Minerals
          if (ast_minerals > 100000) then
            set ast_minerals := 150 + (ast_minerals / 10000)
          endif
          // Organics
          if (ast_organics > 100000) then
            set ast_organics := 150 + (ast_organics / 10000)
          endif
          // Radioactives
          if (ast_radioactives > 100000) then
            set ast_radioactives := 150 + (ast_radioactives / 10000)
          endif
        endif

        if Is_Remote_Mining_Location_Ok(ast_sys_loc, ast_sect_loc) then
          if ((design_type = "Ship (Remote Mining)") and (ast_minerals >= 150)) or ((design_type = "Ship (Remote Farming)") and (ast_organics >= 150)) or ((design_type = "Ship (Remote Refining)") and (ast_radioactives >= 150)) then
            set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, ast_sys_loc, ast_sect_loc)
            // Set distance modifier
            if (design_type = "Ship (Remote Mining)") then
              set dist_mod := Sys_Trunc((ast_minerals - 150) / 10)
            else
              if (design_type = "Ship (Remote Refining)") then
                set dist_mod := Sys_Trunc((ast_radioactives - 200) / 10)
              else
                set dist_mod := Sys_Trunc((ast_organics - 200) / 10)
              endif
            endif
            // Is this the closest asteroid field?
            if (this_dist < min_dist - dist_mod) then
              set min_dist := this_dist - dist_mod
              set move_sys_loc := ast_sys_loc
              set move_sect_loc := ast_sect_loc
            endif
          endif
        endif
      endfor
    endif

    // Order our ship to move to the asteroid field
    if (move_sys_loc > 0) then
      set orders_given := Sys_Give_Space_Object_Order_MoveTo(ship_id, move_sys_loc, move_sect_loc)
      // Debug output
      set sys_name := Sys_Get_Solar_System_Name(move_sys_loc) + " system at sector " + Sys_Convert_Long_To_String(move_sect_loc)
      call Sys_Debug_Print("Ships","    - Sent to gather resources in " + sys_name)
    endif
  endif

  // If no orders send our Remote Mining Ship to the nearest Space Yard
  if (not orders_given) then
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Medical_Ships
//------------------------------------------------------------------------
function Minister_Medical_Ships returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  planet_id:                 long
  planet_name:               string
  plague_count:              long
  plague_level:              long
  medical_comp_level:        long
  sobj_sys_loc:              long
  sobj_sect_loc:             long
begin

  // Attempt to send our Medical Ship to cure a plague
  if (lst_AI_Our_Plagued_Colonies.count() > 0) then
    set planet_id := lst_AI_Our_Plagued_Colonies.get(1)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set plague_level := Sys_Get_Planet_Plague_Level(planet_id)
    set medical_comp_level := Get_Component_Level(ship_id, Sys_Get_Component_With_Name(sys_long_Player_ID, "Medical Bay"))
    set sobj_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)

    if (ship_id > 0) then
      if (plague_level <= medical_comp_level) then
        set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, sobj_sys_loc, sobj_sect_loc)
        call lst_AI_Our_Plagued_Colonies.delete(1)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Ordered to cure plague on " + planet_name)
      else
        set bool_Race_Cannot_Cure_Plague := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "    - Cannot cure plague on " + planet_name)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Cloaking
//------------------------------------------------------------------------
function Minister_Cloaking returns boolean
params
  ship_id:                   long
vars
  has_cloaking_device:       boolean := FALSE
  has_stealth_armor:         boolean := FALSE
  has_stealth_totem:         boolean := FALSE
  cloak_ship:                boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_supply:               long
  design_id:                 long
begin

  // Note our ship's location, current supplies, and if it has a cloaking device or cloaking armor
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
  set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
  set has_cloaking_device := Sys_Does_Vehicle_Design_Have_Component_With_Name(design_id, "Cloaking Device")
  set has_stealth_armor := Sys_Does_Vehicle_Design_Have_Component_With_Name(design_id, "Stealth Armor")
  set has_stealth_totem := Sys_Does_Vehicle_Design_Have_Component_With_Name(design_id, "Stealth Totem")

  // If our ship with a cloaking device is in a location that has enemies present, cloak the ship
  if (has_cloaking_device) then
    if (lst_AI_Defense_Location_System.indexof(ship_sys_loc) <> 0) or (lst_AI_Attack_Location_System.indexof(ship_sys_loc) <> 0) then
      set cloak_ship := TRUE
    endif

    // Order our ship to cloak or de-cloak
    if (cloak_ship) and (ship_supply > 1000) then
      call Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CLOAK, 0, 0, 0)
      // Debug output
      call Sys_Debug_Print("Ships", " -  Ordered to cloak (Cloaking Device)")
    else
      call Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DECLOAK, 0, 0, 0)
      // Debug output
      call Sys_Debug_Print("Ships", " -  Ordered to decloak (Cloaking Device)")
    endif

  endif

  // If our ship has Stealth Armor or a Stealth Totem, activate it
  if (not cloak_ship) and (has_stealth_armor) or (has_stealth_totem) then
    set cloak_ship := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CLOAK, ship_sys_loc, ship_sect_loc, ship_id)
    // Debug output
    call Sys_Debug_Print("Ships", " -  Ordered to cloak (Armor or Totem)")
  endif

  return cloak_ship
end

//------------------------------------------------------------------------
// Minister_Mothballing
//------------------------------------------------------------------------
function Minister_Mothballing returns boolean
params
  ship_id:                   long
  ship_status:               long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_resources:            resources
  maint_minerals:            real
  maint_organics:            real
  maint_radioactives:        real
  activate_minerals:         real
  activate_organics:         real
  activate_radioactives:     real
  design_type:               string
  planet_id:                 long
  design_in_demand:          boolean := FALSE
  num_mothball:              long
  max_num_mothball:          long
  SY_present:                boolean := FALSE
  skip_mothball:             boolean := FALSE
  mothball_ship:             boolean := FALSE
  unmothball_ship:           boolean := FALSE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set design_type := Get_General_AI_Design_Type(Sys_Get_Space_Object_AI_Design_Type(ship_id))
  // Is the design type in demand?
  set design_in_demand := Is_Ship_Design_Type_In_Demand(ship_id, "")

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set planet_id := Get_Colony_In_Location(ship_sys_loc, ship_sect_loc)

  // Is there a Space Yard present?
  set SY_present := Sys_Is_Space_Yard_At_Location(sys_long_Player_ID, ship_sys_loc, ship_sect_loc)

  if Sys_Does_Space_Object_Have_Space_Yard(ship_id) and (not Sys_Does_Space_Object_Have_Space_Yard(planet_id)) then
    set SY_present := FALSE
  endif

  // If our ship is mothballed, should it be re-activated?
  if (SY_present) and (ship_status = SHIP_STATUS_MOTHBALLED) then
    // Debug output
    call Sys_Debug_Print("Ships", "    - Mothballed")
    // What is the activation cost?
    set activate_minerals := ship_resources.get(RESOURCE_TYPE_MINERALS) * 0.20
    set activate_organics := ship_resources.get(RESOURCE_TYPE_ORGANICS) * 0.20
    set activate_radioactives := ship_resources.get(RESOURCE_TYPE_RADIOACTIVES) * 0.20
    // If our base is in a with an enemy presence, unmothball it
    if Sys_Is_Space_Object_Base(ship_id) then
      if Is_Enemy_Present_In_System(ship_sys_loc) then
        set unmothball_ship := TRUE
      endif
    endif
    // If we no longer have low resources, unmothball our ship if we could use of its design type
    if ((not bool_Race_Minerals_Low) and (activate_minerals < lng_Minerals_Surplus)) and ((not bool_Race_Organics_Low) and (activate_organics < lng_Organics_Surplus)) and ((not bool_Race_Radioactives_Low) and (activate_radioactives < lng_Radioactives_Surplus)) then
      if (design_in_demand) then
        set unmothball_ship := TRUE
      endif
    endif
  endif

  // Order our ship to unmothball
  if (unmothball_ship) then
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_UNMOTHBALL, ship_sys_loc, ship_sect_loc, 0)
    // Update our resource modifiers
    call Compute_Resource_Balances()
    call Compute_Resource_Levels()
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to unmothball")
  endif

  // Should we mothball our ship?
  if (ship_status = SHIP_STATUS_NORMAL) then
    // Never mothball remote resource ships or colonizers
    set skip_mothball := (design_type = "Ship (Remote Mining)") or (design_type = "Ship (Remote Farming)") or (design_type = "Ship (Remote Refining)") or (design_type = "Colonizer (Rock)") or (design_type = "Colonizer (Ice)") or (design_type = "Colonizer (Gas)")
    // Don't mothball combat and support ships if we are at war
    if (lng_AI_Num_Of_Wars > 0) then
      set skip_mothball := (design_type = "Ship (Attack)") or (design_type = "Ship (Defense)") or (design_type = "Ship (Seeker)") or (design_type = "Ship (Attack Base)") or (design_type = "Ship (Point-Defense)") or (design_type = "Ship (Bombardment)") or (design_type = "Ship (Boarding)") or (design_type = "Ship (Kamikaze)") or (design_type = "Carrier (Fighter)") or (design_type = "Carrier (Drone)") or (design_type = "Transport (Supply)") or (design_type = "Ship (Mine Sweeper)") or (design_type = "Transport (Troop)") or (design_type = "Ship (Repair)")
    endif

    if (not skip_mothball) then
      // Note our ship's maintenance and unmothball resource amounts
      set ship_resources := Sys_Get_Vehicle_Design_Cost(Sys_Get_Space_Object_Vehicle_Design_ID(ship_id))
      set maint_minerals := ship_resources.get(RESOURCE_TYPE_MINERALS) * 0.25
      set maint_organics := ship_resources.get(RESOURCE_TYPE_ORGANICS) * 0.25
      set maint_radioactives := ship_resources.get(RESOURCE_TYPE_RADIOACTIVES) * 0.25
      // Set our maximum number of ships to mothball in a turn
      set num_mothball := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_MOTHBALL, 0, 0, 0)
      set max_num_mothball := Sys_Divide_Long(lng_Minerals_Deficit, 1000)
      set max_num_mothball := Sys_Max_Long(max_num_mothball, Sys_Divide_Long(lng_Organics_Deficit, 1000))
      set max_num_mothball := Sys_Max_Long(max_num_mothball, Sys_Divide_Long(lng_Radioactives_Deficit, 1000))
      // Increase our mothball limit if we have chronic maintenance issues
      if (bool_Race_Maintenance_Cont_High) then
        set max_num_mothball := Sys_Trunc(max_num_mothball * 1.5)
      endif

      // Check to see if our ship should be mothballed
      if (num_mothball < max_num_mothball) then
        if ((bool_Race_Minerals_Low) and (maint_minerals > 1000)) or ((bool_Race_Organics_Low) and (maint_Organics > 1000)) or ((bool_Race_Radioactives_Low) and (maint_radioactives > 1000)) or (bool_Race_Maintenance_High) then
          if Sys_Is_Space_Object_Base(ship_id) then
          // Mothball our defense bases in systems that are not Defense locations
            if ((design_type = "Base (Defense)") and (lst_AI_Defense_Location_System.indexof(ship_sys_loc) <= 0)) or (not bool_Race_Is_Not_Alone) then
              set mothball_ship := TRUE
            endif
            if (design_type = "Base (Space Yard)") and (not design_in_demand) then
              set mothball_ship := TRUE
            endif
          else
            // Mothball our ship
            if (not design_in_demand) then
              set mothball_ship := TRUE
            endif
          endif
        endif
      endif
    endif
  endif

  // Order our ship to be mothballed
  if (mothball_ship) then
    if (SY_Present) then
      set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOTHBALL, ship_sys_loc, ship_sect_loc, 0)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to mothball at its current location")
    else
      set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
      set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOTHBALL, gbl_SY_sys_loc, gbl_SY_sect_loc, 0)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to mothball at " + Sys_Get_Space_Object_Name(gbl_SY_location))
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Naming
//------------------------------------------------------------------------
function Minister_Naming returns boolean
params
  ship_id:                   long
vars
  ship_name:                 string
  ship_name_count:           long
  ship_name_index:           long
  root_ship_name:            string
  base_ship_name:            string
  design_id:                 long
  design_name:               string
  new_ship_name:             string
  skip_name:                 boolean := FALSE
begin

  // Get our ship's details
  set ship_name := Sys_Get_Space_Object_Name(ship_id)
  set ship_name_count := Sys_Length_String(ship_name)
  set root_ship_name := Sys_Delete_String(ship_name, ship_name_count - 4, 5)
  set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
  set design_name := Sys_Get_Vehicle_Design_Name(design_id)

  // Does our design have a ^ marker to retain a portion of its name?
  set ship_name_index := Sys_Pos_String("^", ship_name)

  if (ship_name_index > 0) then
    set root_ship_name := Sys_Delete_String(ship_name, 1, ship_name_index + 1)
    set ship_name_count := Sys_Length_String(root_ship_name)
    set root_ship_name := Sys_Delete_String(root_ship_name, ship_name_count - 4, 5)
  endif

  // Don't attempt to rename our ship if its name contains an asterisk
  if (Sys_Pos_String("*", ship_name) > 0) or (root_ship_name = design_name) then
    set skip_name := TRUE
  endif

  // If our ship's root name does not match its design name, then rename it
  if (not skip_name) then
    set new_ship_name := Sys_Replace_String(ship_name, root_ship_name, design_name, TRUE, TRUE)
    call Sys_Set_Space_Object_Name(ship_id, new_ship_name)
    // Debug output
    call Sys_Debug_Print("Ships", "  - Renamed to " + new_ship_name)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Minister_Stellar_OpenWarpPoint
//------------------------------------------------------------------------
function Minister_Stellar_OpenWarpPoint returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  wp_comp_level:             long
  max_wp_dist:               long
  max_num_wp:                long
  list_count:                long := 0
  list_index:                long := 0
  sys_loc:                   long
  orig_sys_loc:              long
  orig_sect_loc:             long
  orig_sys_name:             string
  dest_sys_loc:              long
  dest_sect_loc:             long
  dest_sys_name:             string
  colony_sys_count:          long
  colony_sys_index:          long
  colony_sys_loc:            long
  colony_sect_loc:           long
  this_dist:                 long
  min_dist:                  long := 999999
  skip_system:               boolean := FALSE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set wp_comp_level := Sys_Get_Space_Object_Comp_Info_Comp_Level(ship_id, Get_Component_Index(ship_id, Sys_Get_Component_With_Name(sys_long_Player_ID, "Gravitational Quantum Resonator")))

  // Get the maximum distance we can open a warp point to
  set max_wp_dist := wp_comp_level * 5

  // Debug output
  call Sys_Debug_Print("Ships", "    - Has Gravitational Quantum Resonator level " + Sys_Convert_Long_To_String(wp_comp_level))

  // Set the max number of warp points for the system the ship is in
  if (Sys_Get_Empire_Home_System(sys_long_Player_ID) <> ship_sys_loc) then
    set max_num_wp := 10
  else
    set max_num_wp := 10
  endif

  // If this system has a System Gravitational Shield, don't try to open a warp point from it
  set skip_system := Is_System_Protected(ship_sys_loc) or (Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, ship_sys_loc) >= max_num_wp)

  // Attempt to connect systems that are not connected from our ship's current system
  if (not skip_system) then
    set orig_sys_loc := ship_sys_loc
    set orig_sect_loc := Sys_Get_Random_Empty_Sector(ship_sys_loc)
    set orig_sys_name := Sys_Get_Solar_System_Name(ship_sys_loc)

    // If we are in a disconnected system, find the nearest safe destination system
    if (lst_AI_Our_Not_Connected_Systems.indexof(orig_sys_loc) > 0) then
      // Nearest system with a colony
      set dest_sys_loc := Find_Nearest_System_By_Lightyears(orig_sys_loc, max_wp_dist, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE)
      // If there are no nearby destination systems with a colony, nearest non-enemy system will do
      if (dest_sys_loc = 0) then
        set dest_sys_loc := Find_Nearest_System_By_Lightyears(orig_sys_loc, max_wp_dist, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
        set dest_sys_name := Sys_Get_Solar_System_Name(dest_sys_loc)
      endif
    endif

    // Do we have a disconnected system in range we should connect to?
    if (dest_sys_loc = 0) then
      set list_count := lst_AI_Our_Not_Connected_Systems.count()

      if (list_count > 0) then
        loop
          set list_index := list_index + 1
          set sys_loc := lst_AI_Our_Not_Connected_Systems.get(list_index)
          set this_dist := Sys_Get_Lightyear_Distance_Between_Systems(orig_sys_loc, sys_loc)
          // Is this the closest disconnected system?
          if (this_dist < min_dist) and (this_dist < max_wp_dist) and (orig_sys_loc <> sys_loc) then
            set dest_sys_loc := sys_loc
            set dest_sys_name := Sys_Get_Solar_System_Name(dest_sys_loc)
          endif
          exitwhen (list_index >= list_count)
        endloop
      endif
    endif

    // Is there a nearby system with a colony (or colonies) that we should connect to?
    if (dest_sys_loc = 0) then
      set dest_sys_loc := Find_Nearest_System_By_Lightyears(orig_sys_loc, max_wp_dist, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE)
      set dest_sys_name := Sys_Get_Solar_System_Name(dest_sys_loc)
    endif

    // Is there a nearby system without enemies that we are not connected to?
    if (dest_sys_loc = 0) then
      set dest_sys_loc := Find_Nearest_System_By_Lightyears(orig_sys_loc, max_wp_dist, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
      set dest_sys_name := Sys_Get_Solar_System_Name(dest_sys_loc)
    endif

    // Pending - Warp to Enemy System

    // Order our ship to create a warp point
    if (dest_sys_loc > 0) then
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, orig_sys_loc, orig_sect_loc)
      set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_OPEN_WP, 0, 0, dest_sys_loc)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to open a Warp Point from the " + orig_sys_name + " System to the " + dest_sys_name + " System")
      // If the destination system has mobile enemies present, move our ship away from the WP after we open it
      if Is_Enemy_Present_In_System(dest_sys_loc) then
        set orders_given := Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
      endif
    endif
  endif

  // Order our ship to repair if it can't repair itself after opening a warp point
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // Check to see if we can make new warp points to systems that are not connected at all to our current ones
  if (not orders_given) then
    set colony_sys_count := lst_AI_Our_Colony_Systems.count()
    // Go through our systems with colonies and find the nearest colony system with the possibility of new warp connections
    if (colony_sys_count > 0) then
      set min_dist := 999999

      for colony_sys_index := 1 to colony_sys_count do
        if (lst_AI_Our_Colony_Systems.get(colony_sys_index) = 1) then
          set colony_sys_loc := colony_sys_index
          set colony_sect_loc := Get_A_Colony_Location_In_System(colony_sys_loc)
          // Find the nearest truly disconnected system to our colony system
          if (Find_Nearest_System_By_Lightyears(colony_sys_loc, max_wp_dist, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE) > 0) then
            set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, colony_sys_loc, colony_sect_loc)
            // Is this the nearest colony system?
            if (this_dist < min_dist) then
              set min_dist := this_dist
              set dest_sys_loc := colony_sys_loc
              set dest_sect_loc := colony_sect_loc
            endif
          endif
        endif
      endfor
    endif

    // Go to another system with a colony to see if we can make warp points there
    if (dest_sys_loc > 0) then
      set dest_sys_name := Sys_Get_Solar_System_Name(dest_sys_loc)
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, dest_sys_loc, dest_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to " + dest_sys_name + " System in order to make new warp points to disconnected systems")
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CloseWarpPoint
//------------------------------------------------------------------------
function Minister_Stellar_CloseWarpPoint returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  list_index:                long
  wp_id:                     long
  wp_sys_loc:                long
  wp_dest_sys_loc:           long
  wp_sect_loc:               long
  sys_name:                  string
  dest_sys_name:             string
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Attempt to close warp points leading to hostile systems
  set list_count := lst_AI_Warp_Points_To_Close_ID.count()

  if (list_count > 0) then
    set wp_id := Find_Nearest_Object_In_List(lst_AI_Warp_Points_To_Close_ID, ship_sys_loc, ship_sect_loc, TRUE, FALSE)
    set wp_sys_loc := Sys_Get_Space_Object_System_Location(wp_id)
    set wp_sect_loc := Sys_Get_Space_Object_Sector_Location(wp_id)
    set wp_dest_sys_loc := lst_AI_Warp_Points_To_Close_Dest_Sys.get(lst_AI_Warp_Points_To_Close_ID.indexof(wp_id))
    set sys_name := Sys_Get_Solar_System_Name(wp_sys_loc)
    set dest_sys_name := Sys_Get_Solar_System_Name(wp_dest_sys_loc)
    // Order our ship to close the warp point
    if  (lst_AI_System_To_Avoid.indexof(wp_sys_loc) <= 0) then
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, wp_sys_loc, wp_sect_loc)
      set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CLOSE_WP, 0, 0, wp_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to close a Warp Point in " + sys_name + " System leading to the " + dest_sys_name + " System")
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CreatePlanet
//------------------------------------------------------------------------
function Minister_Stellar_CreatePlanet returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  list_index:                long := 0
  ast_id:                    long
  ast_sys_loc:               long
  ast_sect_loc:              long
  sys_name:                  string
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Find the nearest asteroid field to make into a planet
  set list_count := lst_AI_Asteroid_Fields_For_Planets.count()

  if (list_count > 0) then
    set ast_id := Find_Nearest_Object_In_List(lst_AI_Asteroid_Fields_For_Planets, ship_sys_loc, ship_sect_loc, TRUE, FALSE)
    set ast_sys_loc := Sys_Get_Space_Object_System_Location(ast_id)
    set ast_sect_loc := Sys_Get_Space_Object_Sector_Location(ast_id)
    set sys_name := Sys_Get_Solar_System_Name(ast_sys_loc)
    // Order our ship to move to the asteroid field and create a planet
    set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, ast_sys_loc, ast_sect_loc)
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CREATE_PLANET, 0, 0, 0)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to create a Planet in " + sys_name + " System")
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_DestroyPlanet
//------------------------------------------------------------------------
function Minister_Stellar_DestroyPlanet returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  comp_level:                long
  planet_id:                 long
  planet_name:               string
  planet_sys_loc:            long
  planet_sect_loc:           long
  planet_size:               long
  list_index:                long
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set comp_level := Sys_Get_Space_Object_Comp_Info_Comp_Level(ship_id, Get_Component_Index(ship_id, Sys_Get_Component_With_Name(sys_long_Player_ID, "Tectonic Bomb")))

  // Debug output
  call Sys_Debug_Print("Ships", "    - Has Tectonic Bomb level " + Sys_Convert_Long_To_String(comp_level))

  // Priority 1 - Destroy enemy breathable planets at our attack locations
  set planet_id := Find_Nearest_Object_In_List(lst_AI_Planets_To_Destroy, ship_sys_loc, ship_sect_loc, FALSE, FALSE)
  set planet_name := Sys_Get_Space_Object_Name(planet_id)
  set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
  set planet_sect_loc :=  Sys_Get_Space_Object_Sector_Location(planet_id)
  set planet_size := Get_Planet_Size(planet_id)

  // Order our ship to destroy the planet
  if (planet_size > 0) and (planet_size <= comp_level) then
    set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, planet_sys_loc, planet_sect_loc)
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DESTROY_PLANET, 0, 0, planet_id)
    if (orders_given) then
      set list_index := lst_AI_Planets_To_Destroy.indexof(planet_id)
      // Remove the planet from our list of planets to destroy
      call lst_AI_Planets_To_Destroy.delete(list_index)
      call lst_AI_Planets_To_Destroy_Distance.delete(list_index)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Destroy planet " + planet_name)
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CreateStar
//------------------------------------------------------------------------
function Minister_Stellar_CreateStar returns boolean
params
  ship_id:                   long
vars
  list_count:                long
  list_index:                long
  lst_nebulae_sys:           longlist
  nebulae_sys_loc:           long
  nebulae_sect_loc:          long
  sys_name:                  string
  orders_given:              boolean := FALSE
begin

  // Check nearby nebulae to see if they are near our colonies
  if (not orders_given) then
    set list_count := Sys_Get_List_Of_Nebulae(lst_nebulae_sys)

    if (list_count > 0) then
      loop
        set list_index := list_index + 1
        set nebulae_sys_loc := lst_nebulae_sys.get(list_index)
        set nebulae_sect_loc := Sys_Get_Random_Empty_Sector(nebulae_sys_loc)
        set sys_name := Sys_Get_Solar_System_Name(nebulae_sys_loc)

        // If we have colonies adjacent to the nebulae, we should make it a star instead
        if Sys_Have_Seen_System(sys_long_Player_ID, nebulae_sys_loc) then
          if Do_We_Have_Colonies_In_Adjacent_Systems(nebulae_sys_loc) then
            // Create a star from the Nebula
            set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, nebulae_sys_loc, nebulae_sect_loc)
            set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CREATE_SUN, 0, 0, 0)
            // Debug output
            call Sys_Debug_Print("Ships", "    - Ordered to turn the Nebula in " + sys_name + " System into a Star")
          endif
        endif
        exitwhen (list_index >= list_count) or (orders_given)
      endloop
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_DestroyStar
//------------------------------------------------------------------------
function Minister_Stellar_DestroyStar returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  star_id:                   long
  star_name:                 string
  star_sys_loc:              long
  star_sect_loc:             long
  list_index:                long
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Priority 1 - Destroy stars in our enemies' systems
  set star_id := Find_Nearest_Object_In_List(lst_AI_Stars_To_Destroy, ship_sys_loc, ship_sect_loc, FALSE, FALSE)
  set star_name := Sys_Get_Space_Object_Name(star_id)
  set star_sys_loc := Sys_Get_Space_Object_System_Location(star_id)
  set star_sect_loc :=  Sys_Get_Space_Object_Sector_Location(star_id)

  // Order our ship to destroy the star
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOVE_NEAR, star_sys_loc, star_sect_loc, star_id)
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DESTROY_SUN, 0, 0, star_id)

  if (orders_given) then
    set list_index := lst_AI_Stars_To_Destroy.indexof(star_id)
    // Remove the star from our list of stars to destroy
    call lst_AI_Stars_To_Destroy.delete(list_index)
    call lst_AI_Stars_To_Destroy_Distance.delete(list_index)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to destroy star " + star_name)
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CreateStorm
//------------------------------------------------------------------------
function Minister_Stellar_CreateStorm returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
begin

  // Priority 1 - Create Storms

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_DestroyStorm
//------------------------------------------------------------------------
function Minister_Stellar_DestroyStorm returns boolean
params
  ship_id:                   long
vars
  ship_name:                 string
  list_count:                long
  list_index:                long
  storm_id:                  long
  storm_sys_loc:             long
  storm_sect_loc:            long
  sys_name:                  string
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_name := Sys_Get_Space_Object_Name(ship_id)

  // Remove storms from our systems with colonies
  if (not orders_given) then
    set list_count := lst_AI_Storms_To_Destroy.count()

    if (list_count > 0) then
      loop
        set list_index := list_index + 1
        set storm_id := lst_AI_Storms_To_Destroy.get(list_index)
        set storm_sys_loc := Sys_Get_Space_Object_System_Location(storm_id)
        set storm_sect_loc := Sys_Get_Space_Object_Sector_Location(storm_id)
        set sys_name := Sys_Get_Solar_System_Name(storm_sys_loc)
        // Destroy the Storm
        if (not Is_Enemy_Present_In_Sector(storm_sys_loc, storm_sect_loc)) then
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, storm_sys_loc, storm_sect_loc)
          set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DESTROY_STORM, 0, 0, storm_id)
          // Remove the storm from our list
          if (orders_given) then
            call lst_AI_Storms_To_Destroy.delete(list_index)
            call lst_AI_Storms_To_Destroy_Distance.delete(list_index)
          endif
          // Debug output
          call Sys_Debug_Print("Ships", "    - Ordered to destroy a Storm in " + sys_name + " System")
        endif
        exitwhen (list_index >= list_count) or (orders_given)
      endloop
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CreateBlackHole
//------------------------------------------------------------------------
function Minister_Stellar_CreateBlackHole returns boolean
params
  ship_id:                   long
vars
  ship_name:                 string
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  list_index:                long
  star_id:                   long
  star_name:                 string
  star_sys_loc:              long
  star_sect_loc:             long
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Priority 1 - Create black holes in our enemies' systems
  set star_id := Find_Nearest_Object_In_List(lst_AI_Stars_To_Destroy, ship_sys_loc, ship_sect_loc, FALSE, FALSE)
  set star_name := Sys_Get_Space_Object_Name(star_id)
  set star_sys_loc := Sys_Get_Space_Object_System_Location(star_id)
  set star_sect_loc :=  Sys_Get_Space_Object_Sector_Location(star_id)

  // Order our ship to destroy the star and create a black hole
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOVE_NEAR, star_sys_loc, star_sect_loc, star_id)
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CREATE_BLACK_HOLE, 0, 0, star_id)
  // Debug output
  if (orders_given) then
    call Sys_Debug_Print("Ships", "    - Ordered to create a black hole from the star " + star_name)
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_DestroyBlackHole
//------------------------------------------------------------------------
function Minister_Stellar_DestroyBlackHole returns boolean
params
  ship_id:                   long
vars
  home_sys_loc:              long
  list_count:                long
  list_index:                long
  lst_blackhole_sys:         longlist
  blackhole_sys_loc:         long
  blackhole_sect_loc:        long
  sys_name:                  string
  orders_given:              boolean := FALSE
begin

  // Get our home system's location
  set home_sys_loc := Sys_Get_Empire_Home_System(sys_long_Player_ID)

  // Check for nearby Black Holes
  if (not orders_given) then
    set list_count := Sys_Get_List_Of_Black_Holes(lst_blackhole_sys)

    if (list_count > 0) then
      loop
        set list_index := list_index + 1
        set blackhole_sys_loc := lst_blackhole_sys.get(list_index)
        set blackhole_sect_loc := Sys_Get_Random_Empty_Sector(blackhole_sys_loc)
        set sys_name := Sys_Get_Solar_System_Name(blackhole_sys_loc)

        // Is the Black Hole close to us?
        if Sys_Have_Seen_System(sys_long_Player_ID, blackhole_sys_loc) then
          if (Sys_Get_System_Distance_Between_Solar_Systems(home_sys_loc, blackhole_sys_loc) < 10) then
            // If its not adjacent to our enemies, we should destroy it
            if (not Does_Enemy_Have_Colony_In_Adjacent_Systems(blackhole_sys_loc)) then
              // Destroy the Black Hole
              set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, blackhole_sys_loc, blackhole_sect_loc)
              set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DESTROY_BLACK_HOLE, 0, 0, 0)
              // Debug output
              call Sys_Debug_Print("Ships", "    - Ordered to destroy the Black Hole in " + sys_name + " System")
            endif
          endif
        endif
        exitwhen (list_index >= list_count) or (orders_given)
      endloop
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_CreateNebulae
//------------------------------------------------------------------------
function Minister_Stellar_CreateNebulae returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  list_index:                long
  star_id:                   long
  star_name:                 string
  star_sys_loc:              long
  star_sect_loc:             long
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Priority 1 - Create Nebulae in our enemies' systems
  set star_id := Find_Nearest_Object_In_List(lst_AI_Stars_To_Destroy, ship_sys_loc, ship_sect_loc, FALSE, FALSE)
  set star_name := Sys_Get_Space_Object_Name(star_id)
  set star_sys_loc := Sys_Get_Space_Object_System_Location(star_id)
  set star_sect_loc :=  Sys_Get_Space_Object_Sector_Location(star_id)

  // Order our ship to create a nebulae from the selected star
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOVE_NEAR, star_sys_loc, star_sect_loc, star_id)
  set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_CREATE_NEBULAE, 0, 0, star_id)
  // Debug output
  if (orders_given) then
    call Sys_Debug_Print("Ships", "    - Ordered to create a nebula from the star " + star_name)
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Minister_Stellar_DestroyNebulae
//------------------------------------------------------------------------
function Minister_Stellar_DestroyNebulae returns boolean
params
  ship_id:                   long
vars
  list_count:                long
  list_index:                long
  lst_nebulae_sys:           longlist
  nebulae_sys_loc:           long
  nebulae_sect_loc:          long
  sys_name:                  string
  orders_given:              boolean := FALSE
begin

  // Check nearby nebulae to see if they are near our colonies
  if (not orders_given) then
    set list_count := Sys_Get_List_Of_Nebulae(lst_nebulae_sys)

    if (list_count > 0) then
      loop
        set list_index := list_index + 1
        set nebulae_sys_loc := lst_nebulae_sys.get(list_index)
        set nebulae_sect_loc := Sys_Get_Random_Empty_Sector(nebulae_sys_loc)
        set sys_name := Sys_Get_Solar_System_Name(nebulae_sys_loc)

        // If we have colonies adjacent to the nebulae, we should destroy it
        if Sys_Have_Seen_System(sys_long_Player_ID, nebulae_sys_loc) then
          if Do_We_Have_Colonies_In_Adjacent_Systems(nebulae_sys_loc) then
            // Destroy the Black Hole
            set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, nebulae_sys_loc, nebulae_sect_loc)
            set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_DESTROY_NEBULAE, 0, 0, 0)
            // Debug output
            call Sys_Debug_Print("Ships", "    - Ordered to destroy the Nebula in " + sys_name + " System")
          endif
        endif
        exitwhen (list_index >= list_count) or (orders_given)
      endloop
    endif
  endif

  // Order our ship to repair if it can't repair itself
  if (orders_given) then
    if (not Can_Ship_Repair_Itself(ship_id)) then
      call Ship_Order_Go_To_SY(ship_id, FALSE)
    endif
  endif

  // If no other orders, go to our nearest colony
  if (not orders_given) then
    call Ship_Order_Go_To_Nearest_Colony(ship_id, FALSE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Evaluate_Current_Orders
//------------------------------------------------------------------------
function Evaluate_Current_Orders returns boolean
params
  ship_id:                   long
vars
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_movement:             long
  ship_num_damaged_comps:    long
  ship_at_spaceyard:         boolean := FALSE
  ship_dest_sys:             long
  ship_dest_sect:            long
  ship_dest_target:          long
  ship_dest_target_type:     long
  ship_has_cargo:            boolean := FALSE
  design_type:               string
  fleet_id:                  long
  fleet_sys_loc:             long
  fleet_sect_loc:            long
  current_orders:            long
  secondary_orders:          long
  comp_name:                 string
  clear_orders:              boolean := FALSE
  keep_orders:               boolean := TRUE
  orders_given:              boolean := FALSE
begin

  // Get our ship's details
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_num_damaged_comps := Sys_Get_Space_Object_Number_Of_Damaged_Components(ship_id)
  set ship_at_spaceyard := Sys_Is_Space_Yard_At_Location(sys_long_Player_ID, ship_sys_loc, ship_sect_loc)
  set ship_dest_sys := Sys_Get_Space_Object_Order_System_Location(ship_id, 1)
  set ship_dest_sect := Sys_Get_Space_Object_Order_Sector_Location(ship_id, 1)
  set ship_dest_target := Sys_Get_Space_Object_Order_Target_Space_Object_ID(ship_id, 1)
  set ship_dest_target_type := Sys_Get_Space_Object_Type(ship_dest_target)
  set ship_has_cargo := Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id)

  set current_orders := Sys_Get_Space_Object_Order_Type(ship_id, 1)

  // Debug output
  call Sys_Debug_Print("Ships", "    - Executing order " + Get_Order_Name(current_orders))

  // Does our ship have a secondary order?
  if (Sys_Get_Space_Object_Order_Count(ship_id) > 1) then
    set secondary_orders := Sys_Get_Space_Object_Order_Type(ship_id, 2)
  endif

  // Has our ship become disabled and can no longer complete its orders?
  if (ship_movement = 0) and (not ship_at_spaceyard) then
    set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Cleared orders because it is disabled")
  endif

  // Is our ship recently retrofitted and needs more time to repair?
  if (ship_at_spaceyard) and (ship_num_damaged_comps > 2) then
    set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
    set orders_given := clear_orders
    // Debug output
    call Sys_Debug_Print("Ships", "    - Cleared orders as still repairing at Space Yard")
  endif

  // Does our ship have orders to explore or survey and doesn't have sensors?
  if (current_orders = ORDER_EXPLORE) or (Secondary_orders = ORDER_EXPLORE) or (current_orders = ORDER_SURVEY_SYSTEM) or (secondary_orders = ORDER_SURVEY_SYSTEM) then
    // Make sure our ship has working basic sensors
    if Is_Component_Damaged(ship_id, "Basic Sensors") then
      set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Cleared survey/explore orders because it has no sensors")
      // Order it to repair
      set orders_given := Send_Ship_To_Repair(ship_id)
    endif
    if (Sys_Get_System_Distance_Between_Solar_Systems(ship_sys_loc, ship_dest_sys) > 5) then
      set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Cleared survey/explore orders because the target system is too far")
    endif
  endif

  // Does our ship have no cargo but ordered to drop or launch cargo?
  if (current_orders = ORDER_DROP) or (secondary_orders = ORDER_DROP) or (current_orders = ORDER_LAUNCH_UNITS) or (secondary_orders = ORDER_LAUNCH_UNITS) then
    if (not ship_has_cargo) then
      set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Cleared its launch/drop orders because it doesn't have cargo")
    endif
  endif

  // Is our ship's destination safe?
  if (design_type <> "Ship (Mine Sweeper)") then
    if (current_orders = ORDER_MOVETO) and Is_Enemy_Present_In_Sector(ship_dest_sys, ship_dest_sect) then
      set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
      call Sys_Debug_Print("Ships", "    - Cleared its orders due to an enemy presence at its destination")
    endif
  endif

  // Don't have our ships survey systems with enemy colonies
  if (current_orders = ORDER_SURVEY_SYSTEM) and Does_Enemy_Have_Colony_In_System(ship_dest_sys) then
    set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
    call Sys_Debug_Print("Ships", "    - Cleared its survey orders due to an enemy presence in the destination system")
  endif

  // Is our colonizing target still valid?
  if (current_orders = ORDER_COLONIZE) or (secondary_orders = ORDER_COLONIZE) then
    set ship_dest_target := Sys_Get_Space_Object_Order_Target_Space_Object_ID(ship_id, 2)
    set ship_dest_target_type := Sys_Get_Space_Object_Type(ship_dest_target)
    // Is our target an owned planet?
    if (ship_dest_target_type = SPACE_OBJECT_TYPE_PLANET) then
      if (Sys_Get_Space_Object_Owner(ship_dest_target) > 0) or (not Can_System_Be_Colonized(ship_dest_sys)) or Does_Enemy_Have_Colony_In_System(ship_dest_sys) then
        set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Cleared its orders since the planet can no longer be colonized")
      endif
    endif
    // Are we colonizing the targeted planet this turn?
    if (Sys_Get_Hex_Distance_Between_Sectors(sys_long_player_ID, ship_sys_loc, ship_sect_loc, ship_dest_sys, ship_dest_sect) < (ship_movement - 1)) then
      set lng_Num_Planets_Colonized_This_Turn := lng_Num_Planets_Colonized_This_Turn + 1
    endif
    // Check our colony ship's colony module
    case design_type
      "Colonizer (Rock)":
        set comp_name := "Rock Colony"
      "Colonizer (Ice)":
        set comp_name := "Ice Colony"
      "Colonizer (Gas)":
        set comp_name := "Gas Giant Colony"
    endcase
    // Is our ship's colony module damaged?
    if Is_Component_Damaged(ship_id, comp_name) then
      set clear_orders := Sys_Space_Object_Clear_Orders(ship_id)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Cleared its orders due to damaged colonization module")
      // Order it to repair
      set orders_given := Send_Ship_To_Repair(ship_id)
    endif
  endif

  // Make available for new orders or have new ones already been given?
  if (clear_orders) then
    if (orders_given) then
      return TRUE
    else
      return FALSE
    endif
  else
    // Maintain our ships previous status if it has not changed
    if (lst_AI_Our_Prev_Ships.indexof(ship_id) > 0) then
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), lst_AI_Our_Prev_Ships_Status.indexof(lst_AI_Our_Prev_Ships.indexof(ship_id)))
    endif
    return TRUE
  endif
end

//------------------------------------------------------------------------
// Send_Ship_To_Repair
//------------------------------------------------------------------------
function Send_Ship_To_Repair returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_movement:             long
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_fleet_id:             long
  num_comps:                 long
  dmg_comps:                 long
  dmg_pct:                   long
begin

  // Get our ship's details
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set num_comps := Sys_Get_Space_Object_Comp_Count(ship_id)
  set dmg_comps := Sys_Get_Space_Object_Number_Of_Damaged_Components(ship_id)
  set dmg_pct := Sys_Trunc((dmg_comps / num_comps) * 100)

  // If our ship is immobile and very heavily damaged, have it self-destruct
  if (bool_Are_We_Computer_Player) and (not Sys_Is_Space_Object_Base(ship_id)) then
    if (not Sys_Is_Space_Yard_At_Location(sys_long_player_ID, ship_sys_loc, ship_sect_loc)) then
      if (dmg_pct > 60) and (ship_movement = 0) then
        // Clear our ship's orders
        call Sys_Space_Object_Clear_Orders(ship_id)
        // If the bridge is inoperable, destroy the ship anyway (ie "Fire on it")
        if Is_Component_Damaged(ship_id, "Bridge") then
          // Destroy the ship
          set orders_given := Sys_Space_Object_Take_Damage(ship_id, "Normal", 999999)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Ordered to be fire on")
        else
          // Have the ship self-destruct if the bridge is operable
          set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_SELF_DESTRUCT, ship_sys_loc, ship_sect_loc, 0)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Ordered to self-destruct")
        endif
      endif
    endif
  endif

  // Send our mobile damaged ships to the nearest Space Yard
  if (not orders_given) and (ship_movement > 0) then
    // Order our ship to the nearest Space Yard
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Does_Ship_Need_Resupply
//------------------------------------------------------------------------
function Does_Ship_Need_Resupply returns boolean
params
  ship_id:                   long
vars
  check_resupply:            boolean := TRUE
  needs_resupply:            boolean := FALSE
  supply_used_per_move:      long
  current_supply:            long
  max_supply:                long
  min_supply:                long
  current_ordnance:          long
  max_ordnance:              long
  min_ordnance:              long
  dist_to_resupply:          long
  design_type:               string
  ship_sys:                  long
  ship_sect:                 long
  ship_dest_sys:             long
  ship_dest_sect:            long
  max_move:                  long
begin

  // Get our ship's details
  set ship_sys := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_dest_sys := Sys_Get_Space_Object_Order_System_Location(ship_id, 1)
  set ship_dest_sect := Sys_Get_Space_Object_Order_Sector_Location(ship_id, 1)
  set max_move := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Some of our ships should never be resupplied
  case (design_type)
    "Ship (Kamikaze)":
      set check_resupply := FALSE
    "Colonizer (Rock)":
      set check_resupply := FALSE
    "Colonizer (Ice)":
      set check_resupply := FALSE
    "Colonizer (Gas)":
      set check_resupply := FALSE
    "Ship (Star Destroyer)":
      set check_resupply := FALSE
    "Ship (Black Hole Creator)":
      set check_resupply := FALSE
    "Ship (Nebulae Creator)":
      set check_resupply := FALSE
  endcase

  // Bases should not be ordered to resupply
  if Sys_Is_Space_Object_Base(ship_id) then
    set check_resupply := FALSE
  endif

  // Check to see if our ship has enough supplies to make it to a resupply location
  if (check_resupply) then
    set current_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
    set max_supply := Sys_Get_Space_Object_Maximum_Supply(ship_id)
    set min_supply := Sys_Divide_Long(max_supply, 2)
    set current_ordnance := Sys_Get_Space_Object_Current_Ordnance(ship_id)
    set max_ordnance := Sys_Get_Space_Object_Maximum_Ordnance(ship_id)
    set min_ordnance := Sys_Divide_long(max_ordnance, 4)

    if (current_supply < min_supply) then
      set supply_used_per_move := Sys_Get_Space_Object_Supplies_Used_Per_Move(ship_id)
      set dist_to_resupply := Sys_Get_Distance_To_Nearest_Resupply_Location(sys_long_Player_ID, ship_sys, ship_sect)

      // Decrease supply by the amount we would use this turn if our ship didn't resupply
      set current_supply := current_supply - (max_move * supply_used_per_move)
      // Increase the distance by the amount we would move this turn if our ship didn't resupply
      set dist_to_resupply := dist_to_resupply + max_move

      if ((current_supply / supply_used_per_move) < dist_to_resupply) then
        set needs_resupply := TRUE
      endif

      if (current_ordnance < min_ordnance) then
        set needs_resupply := TRUE
      endif
    endif
  endif

  return needs_resupply
end

//------------------------------------------------------------------------
// Does_Ship_Need_Retrofitting
//------------------------------------------------------------------------
function Does_Ship_Need_Retrofitting returns boolean
params
  ship_id:                   long
  ship_in_fleet:             boolean
vars
  needs_retrofit:            boolean := TRUE
  design_type:               string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_design_id:            long
  ship_design_age:           long
  ship_size_id:              long
  ship_vehicle_size_name:    string
  ship_has_weapons:          boolean
  best_design_id:            long
  best_size_id:              long
  best_vehicle_size_name:    string
  alt_design_type:           string
  alt_design_id:             long
  retrofit_chance:           long := 25
  retrofit_pct_diff:         long
  SY_present:                boolean := FALSE
begin

  // Don't order a retrofit if we have already reached our limit for our turn
  if (Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_RETROFIT, 0, 0, 0) >= lng_Max_Ships_To_Retrofit) then
    set needs_retrofit := FALSE
  endif

  // Reset global retrofit id
  set gbl_design_id := 0

  if (needs_retrofit) then
    // Note our ship's details
    set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
    set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
    set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
    set ship_design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
    set ship_size_id := Sys_Get_Vehicle_Design_Size_ID(ship_design_id)
    set ship_vehicle_size_name := Sys_Get_Vehicle_Design_Size_Name(ship_design_id)
    set ship_has_weapons := (Sys_Get_Space_Object_Number_Of_UnDamaged_Weapons(ship_id) > 0)
    set ship_design_age := sys_long_Game_Date - Sys_Get_Vehicle_Design_Creation_Date(sys_long_Player_ID, ship_design_id)
    set SY_present := Sys_Is_Space_Yard_At_Location(sys_long_Player_ID, ship_sys_loc, ship_sect_loc)

    // Don't attempt to retrofit ships we don't have the technology for
    if (not Sys_Is_Vehicle_Size_Available(sys_long_Player_ID, ship_size_id)) then
      set needs_retrofit := FALSE
      // Debug output
      call Sys_Debug_Print("Ships", "    - Skip retrofit (Unavailable hull)")
    endif

    // Don't retrofit vehicles constructing items
    if (Sys_Get_Construction_Queue_Item_Count(ship_id) > 0) then
      set needs_retrofit := FALSE
      // Debug output
      call Sys_Debug_Print("Ships", "    - Skip retrofit (Building)")
    endif

    // Don't retrofit remote bases that have no Space Yard in the sector
    if (not SY_Present) and Sys_Is_Space_Object_Base(ship_id) then
      set needs_retrofit := FALSE
      // Debug output
      call Sys_Debug_Print("Ships", "    - Skip retrofit (No SY)")
    endif

    // Don't retrofit our ship if it is one of the following types
    case design_type
      "Colonizer (Rock)":
        set needs_retrofit := FALSE
      "Colonizer (Ice)":
        set needs_retrofit := FALSE
      "Colonizer (Gas)":
        set needs_retrofit := FALSE
      "Ship (Kamikaze)":
        set needs_retrofit := FALSE
      "Ship (Remote Mining)":
        set needs_retrofit := FALSE
      "Ship (Remote Farming)":
        set needs_retrofit := FALSE
      "Ship (Remote Refining)":
        set needs_retrofit := FALSE
    endcase

    // Increase retrofit chance based on ship's status
    if (ship_in_fleet) then
      set retrofit_chance := retrofit_chance + 75
    endif

    if (ship_has_weapons) then
      set retrofit_chance := retrofit_chance + 25
    endif

    if (ship_design_age > 50) then
      set retrofit_chance := retrofit_chance + 25
    endif

    // See if our ship is a likely candidate for retrofit
    if (needs_retrofit) and (retrofit_chance < Sys_Get_Random_Long(1, 100)) then
      set needs_retrofit := FALSE
      // Debug output
      call Sys_Debug_Print("Ships", "    - Skip Retrofit")
    endif

    // Has it been long enough to consider a retrofit for our ship?
    if (needs_retrofit) then
      if (ship_design_age >= lng_AI_Design_Time_Until_Retrofit) then
        set best_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, design_type)
        set best_size_id := Sys_Get_Vehicle_Design_Size_ID(best_design_id)
        set best_vehicle_size_name := Sys_Get_Vehicle_Design_Size_Name(best_design_id)
        set retrofit_pct_diff := Calculate_Retrofit_Cost_Difference(ship_id)

        // If no matching design type upgrade, is there another design type upgrade available? (Combat ships only)
        if (best_design_id = 0) then
          set alt_design_type := Find_Alternative_Design_Type_For_Retrofit(design_type, ship_size_id)
          // If there is an alternative design type of the same size, then consider it for retrofit
          if (alt_design_type <> "") then
            set best_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, alt_design_type)
            // Debug output
            call Sys_Debug_Print("Ships", "    - Retrofit to another design type")
          endif
        endif

        // Is there a newer design from this type?
        if (ship_design_id <> best_design_id) and (ship_size_id = best_size_id) then
          // Is the cost difference more than what is allowed?
          if (retrofit_pct_diff > lng_Retrofit_Max_Cost_Difference) then
            set needs_retrofit := FALSE
            // Debug output
            call Sys_Debug_Print("Ships", "    - Skip retrofit (>50% cost)")
          endif
          // Is the cost difference sufficient to make the upgrade worthwhile?
          if (retrofit_pct_diff < lng_Retrofit_Min_Cost_Difference) or (retrofit_pct_diff = 0) then
            set needs_retrofit := FALSE
            // Debug output
            call Sys_Debug_Print("Ships", "    - Skip Retrofit (< 5% cost difference)")
          else
            set gbl_design_id := best_design_id
          endif
        else
          set needs_retrofit := FALSE
        endif
      else
        set needs_retrofit := FALSE
      endif
    endif
  endif

  return needs_retrofit
end

//------------------------------------------------------------------------
// Order_Retrofit
//------------------------------------------------------------------------
function Order_Retrofit returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  design_type:               string
  best_design_id:            long
  new_design_type:           string
  ship_sys_loc:              long
  ship_sect_loc:             long
begin

  // Get our ship's details
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set best_design_id := gbl_design_id
  set new_design_type := Sys_Get_Vehicle_Design_AI_Design_Type(best_design_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Order our ship to a Space Yard for retrofit
  if Sys_Is_Space_Object_Base(ship_id) then
    // Don't give bases a move order
    set gbl_SY_location := Get_Colony_In_Location(ship_sys_loc, ship_sect_loc)
  else
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
  endif

  // Order our ship to drop its cargo before retrofit
  if Sys_Does_Space_Object_Cargo_Have_Non_Supply_Ordnance_Item(ship_id) then
    if (What_Unit_Type_Is_Our_Main_Cargo(ship_id) <> "") then
      set orders_given := Sys_Give_Space_Object_Order_Drop_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "", gbl_SY_location)
    else
      set orders_given := Sys_Give_Space_Object_Order_Drop_All_Cargo(ship_id, CARGO_ITEM_TYPE_POPULATION, "", gbl_SY_location)
    endif
    // Debug output
    Call Sys_Debug_Print("Ships", "    - Ordered to drop cargo before retrofit")
  endif

  // Order the retrofit
  set orders_given := Sys_Give_Space_Object_Order_Retrofit(ship_id, best_design_id)
  call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_RETROFIT)

  // Debug output
  if (orders_given) then
    call Sys_Debug_Print("Ships", "    - Ordered to retrofit from " + design_type + " to " + new_design_type)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Does_Ship_Need_Scrapping
//------------------------------------------------------------------------
function Does_Ship_Need_Scrapping returns boolean
params
  ship_id:                   long
vars
  needs_scrapping:           boolean := FALSE
  design_type:               string
  design_id:                 long
  design_date:               long
  design_age:                long
  design_in_demand:          boolean
  design_ours:               boolean
  design_obsolete:           boolean
  retrofit_pct_cost:         long
  ship_xp:                   long
  ship_sys:                  long
  scrap_chance:              long
begin

  // Get our ship's details
  set ship_sys := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_xp := Sys_Trunc(Sys_Get_Space_Object_Experience(ship_id))
  set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set design_date := Sys_Get_Vehicle_Design_Creation_Date(sys_long_Player_ID, design_id)
  set design_age := Sys_Long_Game_Date - design_date
  set design_in_demand := Is_Ship_Design_Type_In_Demand(ship_id, "")
  set design_ours := Is_Design_ID_Ours(design_id)
  set design_obsolete := Sys_Is_Vehicle_Design_Obsolete(design_id)
  set retrofit_pct_cost := Calculate_Retrofit_Cost_Difference(ship_id)

  // Increase the chance to scrap our ship if we can't retrofit it due to cost
  if (retrofit_pct_cost > lng_Retrofit_Max_Cost_Difference) then
    if (design_ours) then
      set scrap_chance := 50
    else
      set scrap_chance := 75
    endif
  endif

  // Increase the chance to scrap our ship if our maintenance costs are high or resources low
  if (bool_Race_Maintenance_High) and ((bool_Race_Minerals_Low) or (bool_Race_Organics_Low) or (bool_Race_Radioactives_Low)) then
    // Increase the chance to scrap our ship if we have too many of its design type
    if (not design_in_demand) then
      set scrap_chance := scrap_chance + 30
    else
      set scrap_chance := scrap_chance + 10
    endif
  else
    if (not design_in_demand) then
      set scrap_chance := scrap_chance + 20
    endif
  endif

  // Increase the chance to scrap our ship if we are at the maximum number of ships
  if (bool_Race_At_Max_Ships) then
    if (design_age > 20) then
      set scrap_chance := scrap_chance + 10
    endif
  endif

  // Reduce the chance to scrap newer ships
  if (ship_xp < 500) then
    set scrap_chance := scrap_chance - 20
  endif

  // Should we scrap our ship?
  if (lng_Scrap_Ship_Count < lng_Max_Ships_To_Scrap * 5) then
    if (scrap_chance > Sys_Get_Random_Long(1, 100)) or (Sys_Is_Vehicle_Design_Obsolete(design_id) and (design_age > lng_Ship_Obsolete_Time_To_Scrap)) then
      set needs_scrapping := TRUE
    endif
  endif

  // Scrap foreign designs that are not obsolete (to analyze)
  if (not design_ours) and (not design_obsolete) and (not bool_Are_We_Neutral_Player) then
    set needs_scrapping := TRUE
  endif

  // Don't scrap Base Space Yards
  if (design_type = "Base (Space Yard)") then
    set needs_scrapping := FALSE
  endif

  // Don't scrap Defense Bases if they are in defense of border systems
  if (design_type = "Base (Defense S)") or (design_type = "Base (Defense L)") then
    if (lst_AI_Defense_Location_System.indexof(ship_sys) > 0) or (lst_AI_Border_System.indexof(ship_sys) > 0) then
      set needs_scrapping := FALSE
    endif
  endif

  return needs_scrapping
end

//------------------------------------------------------------------------
// Order_Scrap
//------------------------------------------------------------------------
function Order_Scrap returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  design_id:                 long
  design_ours:               boolean := FALSE
  design_obsolete:           boolean := FALSE
begin

  // Get our ship's details
  set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
  set design_ours := Is_Design_ID_Ours(design_id)
  set design_obsolete := Sys_Is_Vehicle_Design_Obsolete(design_id)

  // Order our ship to be scrapped
  if (Sys_Get_Vehicle_Design_Space_Movement(design_id) = 0) then
    set orders_given := Sys_Give_Space_Object_Order_Scrap(ship_id)
  else
    set orders_given := Ship_Order_Go_To_SY(ship_id, TRUE)
    // Can we analyze the design?
    if (design_ours) or (design_obsolete) then
      set orders_given := Sys_Give_Space_Object_Order_Scrap(ship_id)
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_SCRAP)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to Scrap")
    else
      call Sys_Give_Space_Object_Order_Any(ship_id, ORDER_ANALYZE, 0, 0, 0)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to Scrap (Analyze)")
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_ANALYZE)
    endif
    // Add to our scrap ship count
    set lng_Scrap_Ship_Count := lng_Scrap_Ship_Count + 1
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Explore
//------------------------------------------------------------------------
function Send_Ship_To_Explore returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_supply:               long
  ship_sys_loc:              long
  ship_sect_loc:             long
  design_type:               string
  list_count:                long
  list_index:                long
  list_position:             long
  min_dist:                  long := 999999
  this_dist:                 long
  other_dist:                long
  move_sys_loc:              long
  move_sect_loc:             long
  dest_sys_loc:              long
  explore_sys_loc:           long
  explore_sect_loc:          long
  explore_wp_index:          long
  explore_wp_id:             long
  sys_name:                  string
begin

  // Get our ship's details
  set ship_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Note our maximum number of explorers
  set lng_Max_Explorers := lst_AI_Explore_System.count()

  // Find the nearest system with an unexplored warp point for our ship to explore
  if (ship_supply > 1000) and (gbl_lng_explorers_sent_out < lng_Max_Explorers) and (not bool_Are_We_Neutral_Player) then
    set list_count := lst_AI_Explore_System.count()
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set explore_sys_loc := lst_AI_Explore_System.get(list_index)
        set explore_sect_loc := lst_AI_Explore_Sector.get(list_index)
        set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, explore_sys_loc, explore_sect_loc)
        // Is there another ship of our type that is closer?
        set other_dist := Find_Nearest_Ship_Distance_To_Location(explore_sys_loc, explore_sect_loc, TRUE, design_type, TRUE)
        // Find the closest system to explore that has no enemies present
        if (this_dist < min_dist) and (this_dist < other_dist) then
          if (not Is_Enemy_Present_In_Sector(explore_sys_loc, explore_sect_loc)) then
            set min_dist := this_dist
            set move_sys_loc := explore_sys_loc
            set move_sect_loc := explore_sect_loc
            set explore_wp_index := lst_AI_Explore_WP_Index.get(list_index)
            set explore_wp_id := lst_AI_Explore_WP_ID.get(list_index)
            set dest_sys_loc := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, explore_sys_loc, explore_wp_index)
            set list_position := list_index
          endif
        endif
      endfor
    endif

    // Order our ship to explore beyond this system
    if (move_sys_loc > 0) then
      set orders_given := Sys_Give_Space_Object_Order_MoveTo(ship_id, move_sys_loc, move_sect_loc)
      set orders_given := Sys_Give_Space_Object_Order_Warp(ship_id, explore_wp_id)
      set gbl_lng_explorers_sent_out := gbl_lng_explorers_sent_out + 1
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_EXPLORE)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to explore beyond " + Sys_Get_Solar_System_Name(move_sys_loc) + " system")
      // Order our ship to survey the next system
      if (dest_sys_loc > 0) then
        set orders_given := Sys_Give_Space_Object_Order_Survey(ship_id, dest_sys_loc)
        call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_SURVEY)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Ordered to survey " + Sys_Get_Solar_System_Name(dest_sys_loc) + " system")
      endif
      // Remove location to explore
      call lst_AI_Explore_System.delete(list_position)
      call lst_AI_Explore_Sector.delete(list_position)
      call lst_AI_Explore_WP_Index.delete(list_position)
      call lst_AI_Explore_WP_ID.delete(list_position)
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Survey
//------------------------------------------------------------------------
function Send_Ship_To_Survey returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_supply:               long
  ship_sys_loc:              long
  design_type:               string
  list_count:                long
  list_index:                long
  list_position:             long
  survey_sys_loc:            long
  min_dist:                  long := 999999
  this_dist:                 long
  other_dist:                long := 999999
  move_sys_loc:              long
  sys_name:                  string
begin

  // Get our ship's details
  set ship_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Note our maximum number of surveyors
  set lng_Max_Surveyors := lst_AI_Survey_System.count()

  // Find the nearest system for our ship to survey
  if (ship_supply > 2000) and (gbl_lng_surveyors_sent_out <= lng_Max_Surveyors) then
    set list_count := lst_AI_Survey_System.count()
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set survey_sys_loc := lst_AI_Survey_System.get(list_index)
        set this_dist := Sys_Get_System_Distance_Between_Solar_Systems(ship_sys_loc, survey_sys_loc)
        // Are we the closest ship of our type?
        set other_dist := Find_Nearest_Ship_System_Distance_To_Location(survey_sys_loc, TRUE, design_type, TRUE)
        // Find the closest system to survey
        if (this_dist < min_dist) and (this_dist <= other_dist) then
          set min_dist := this_dist
          set move_sys_loc := survey_sys_loc
          set list_position := list_index
        endif
      endfor
    endif

    // Don't bother sending ships to survey far flung systems
    if (min_dist > 5) and (not min_dist = 999999) then
      set move_sys_loc := 0
      call Sys_Debug_Print("Ships", "    - Skipping surveying - all systems too far")
    endif

    // Order our ship to survey the system
    if (move_sys_loc > 0) then
      set orders_given := Sys_Give_Space_Object_Order_Survey(ship_id, move_sys_loc)
      set sys_name := Sys_Get_Solar_System_Name(move_sys_loc)
      set gbl_lng_surveyors_sent_out := gbl_lng_surveyors_sent_out + 1
      // Remove location to survey
      call lst_AI_Survey_System.delete(list_position)
      call lst_AI_Survey_Distance_To_Home.delete(list_position)
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_SURVEY)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to survey " + sys_name)
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Patrol
//------------------------------------------------------------------------
function Send_Ship_To_Patrol returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  index:                     long
  list_count:                long
  list_index:                long
  target_sys_loc:            long
  target_sect_loc:           long
  target_dest_sys_loc:       long
  target_dest_sect_loc:      long
  target_wp_id:              long
  random_sect_loc:           long
  sys_name:                  string
  patrol_type:               string
begin

  // Set our maximum number of patrols
  set lng_Max_Patrols := lst_AI_Patrol_System.count() + lst_AI_Patrol_Secondary_System.count() + lst_AI_Hidden_Enemy_System.count() + lst_AI_Hidden_Other_System.count()

  // Patrol Priority 1 - Patrol warp points leading to enemy or unknown systems
  if (not orders_given) and (gbl_lng_patrols_sent_out <= lng_Max_Patrols) then
    if (lst_AI_Patrol_System.count() > 0) then
      set list_index := Find_Nearest_Destination_In_List(ship_id, lst_AI_Patrol_System, lst_AI_Patrol_Sector)
      // Go to the closest patrol system in the list
      if (list_index > 0) then
        set target_sys_loc := lst_AI_Patrol_System.get(list_index)
        set target_sect_loc := lst_AI_Patrol_Sector.get(list_index)
        set target_dest_sys_loc := lst_AI_Patrol_Dest_System.get(list_index)
        set target_dest_sect_loc := lst_AI_Patrol_Dest_Sector.get(list_index)
        set target_wp_id := lst_AI_Patrol_WP_ID.get(list_index)
        set random_sect_loc := Sys_Get_Random_Empty_Sector(target_sys_loc)
        // Order our ship to the chosen system and remove it from our list of systems to patrol
        if (target_sys_loc > 0) then
          call lst_AI_Patrol_System.delete(list_index)
          call lst_AI_Patrol_Sector.delete(list_index)
          call lst_AI_Patrol_Dest_System.delete(list_index)
          call lst_AI_Patrol_Dest_Sector.delete(list_index)
          // Pick a random empty sector first to cover a bit more ground randomly in the system before heading to the warp point
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, random_sect_loc)
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, target_sect_loc)
          set patrol_type := "Primary"
          // Consider warping to the other system
          if Get_Mine_Group_Count(target_dest_sys_loc, target_dest_sect_loc) = 0 then
            If Is_Enemy_Present_In_Sector(target_dest_sys_loc, target_dest_sect_loc) then
              if (Sys_Get_Random_Long(1, 5) = 1) then
                // Add Warp order
                call Sys_Give_Space_Object_Order_Warp(ship_id, target_wp_id)
                set patrol_type := "Primary + Warp (Enemy)"
              endif
            else
              if (Sys_Get_Random_Long(1, 5) > 1) then
                // Add warp order
                call Sys_Give_Space_Object_Order_Warp(ship_id, target_wp_id)
                set patrol_type := "Primary + Warp (Empty)"
              endif
            endif
            set gbl_lng_patrols_sent_out := gbl_lng_patrols_sent_out + 1
          endif
        endif
      endif
    endif
  endif

  // Patrol Priority 2 - Warp Points leading to systems where we don't have colonies
  if (not orders_given) and (gbl_lng_patrols_sent_out <= lng_Max_Patrols) then
    if (lst_AI_Patrol_Secondary_System.count() > 0) then
      set list_index := Find_Nearest_Destination_In_List(ship_id, lst_AI_Patrol_Secondary_System, lst_AI_Patrol_Secondary_Sector)
      // Go to the closest secondary patrol system in the list
      if (list_index > 0) then
        set target_sys_loc := lst_AI_Patrol_Secondary_System.get(list_index)
        set target_sect_loc := lst_AI_Patrol_Secondary_Sector.get(list_index)
        set random_sect_loc := Sys_Get_Random_Empty_Sector(target_sys_loc)
        // Order our ship to the chosen system and remove it from our list of systems to patrol
        if (target_sys_loc > 0) then
          call lst_AI_Patrol_Secondary_System.delete(list_index)
          call lst_AI_Patrol_Secondary_Sector.delete(list_index)
          // Pick a random empty sector first to cover a bit more ground randomly in the system
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, random_sect_loc)
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, target_sect_loc)
          set patrol_type := "Secondary"
          set gbl_lng_patrols_sent_out := gbl_lng_patrols_sent_out + 1
        endif
      endif
    endif
  endif

  // Patrol Priority 3 - Check out systems with potentially hidden enemies
  if (not orders_given) and (gbl_lng_patrols_sent_out <= lng_Max_Patrols) then
    if (lst_AI_Hidden_Enemy_System.count() > 0) then
      set list_index := Find_Nearest_System_In_List(ship_id, lst_AI_Hidden_Enemy_System)
      // Go the closest system with a hidden enemy
      if (list_index > 0) then
        set target_sys_loc := lst_AI_Hidden_Enemy_System.get(list_index)
        set target_sect_loc := Sys_Get_Random_Empty_Sector(target_sys_loc)
        // Order our ship to the chosen system and remove it from our list of systems to patrol
        if (target_sys_loc > 0) then
          call lst_AI_Hidden_Enemy_System.delete(list_index)
          // Pick a random empty sector first to cover a bit more ground randomly in the system
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, target_sect_loc)
          set patrol_type := "Hidden Enemy"
          set gbl_lng_patrols_sent_out := gbl_lng_patrols_sent_out + 1
        endif
      endif
    endif
  endif

  // Patrol Priority 4 - Check out systems with potentially hidden players (friendly or with treaty)
  if (not orders_given) and (gbl_lng_patrols_sent_out <= lng_Max_Patrols) then
    if (lst_AI_Hidden_Other_System.count() > 0) then
      set list_index := Find_Nearest_System_In_List(ship_id, lst_AI_Hidden_Other_System)
      // Go the closest system with a hidden enemy
      if (list_index > 0) then
        set target_sys_loc := lst_AI_Hidden_Other_System.get(list_index)
        set target_sect_loc := Sys_Get_Random_Empty_Sector(target_sys_loc)
        // Order our ship to the chosen system and remove it from our list of systems to patrol
        if (target_sys_loc > 0) then
          call lst_AI_Hidden_Enemy_System.delete(list_index)
          // Pick a random empty sector first to cover a bit more ground randomly in the system
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_sys_loc, target_sect_loc)
          set patrol_type := "Hidden Other"
          set gbl_lng_patrols_sent_out := gbl_lng_patrols_sent_out + 1
        endif
      endif
    endif
  endif

  // Debug output
  if (orders_given) then
    set sys_name := Sys_Get_Solar_System_Name(target_sys_loc)
    call Sys_Debug_Print("Ships", "    - Ordered to patrol " + sys_name + " (" + patrol_type + ")")
    call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_PATROL)
  endif

  // If no other orders, order our Patrol Ship to escort
  if (not orders_given) then
    set orders_given := Send_Ship_To_Escort(ship_id)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Escort
//------------------------------------------------------------------------
function Send_Ship_To_Escort returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  list_index:                long
  target_id:                 long
  target_name:               string
  target_dist:               long
  target_sys_loc:            long
  target_sect_loc:           long
  target_orders:             long
  target_dest_sys_loc:       long
  target_dest_sect_loc:      long
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Get a list of our ships to escort
  set list_count := lst_AI_Our_Ships_To_Escort.count()

  if (list_count > 0) then
    // Find the closest ship to escort
    set target_id := Find_Nearest_Object_In_List(lst_AI_Our_Ships_To_Escort, ship_sys_loc, ship_sect_loc, FALSE, FALSE)

    if (target_id > 0) then
      set target_name := Sys_Get_Space_Object_Name(target_id)
      set target_sys_loc := Sys_Get_Space_Object_System_Location(target_id)
      set target_sect_loc := Sys_Get_Space_Object_Sector_Location(target_id)
      set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, target_sys_loc, target_sect_loc)

      // Are we in already sector with a ship to escort?
      if (target_dist = 0) then
        set target_orders := Sys_Get_Space_Object_Order_Type(ship_id, 1)
        // Order our ship to move to the destination of the escort target
        if (target_orders > 0) then
          // Does the target ship have a destination?
          set target_dest_sys_loc := Sys_Get_Space_Object_Order_System_Location(target_id, 1)
          set target_dest_sect_loc := Sys_Get_Space_Object_Order_Sector_Location(target_id, 1)
          // If the target has a destination, our escort should be sent there
          if (target_dest_sys_loc > 0) then
            set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, target_dest_sys_loc, target_dest_sect_loc)
            call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_ESCORT)
          endif
          // Debug output
          call Sys_Debug_Print("Ships", "    - Escorting " + target_name)
        else
          // Order our ship to intercept the escort target
          set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOVE_NEAR, target_sys_loc, target_sect_loc, target_id)
          call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_ESCORT)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Ordered to intercept and escort " + target_name + "(" + Sys_Convert_Long_To_String(target_dist) + ")")
        endif
      else
        if (target_dist < 50) then
          // Order our ship to intercept the escort target
          set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_MOVE_NEAR, target_sys_loc, target_sect_loc, target_id)
          call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_ESCORT)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Ordered to intercept and escort " + target_name + "(" + Sys_Convert_Long_To_String(target_dist) + ")")
        endif
      endif
    endif
  endif

  if (orders_given) then
    set list_index := lst_AI_Our_Ships_To_Escort.indexof(target_id)
    // Remove the escort target from our list of ships to escort
    if (list_index > 0) then
      call lst_AI_Our_Ships_To_Escort.delete(list_index)
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Stranded_Ship_To_Roam
//------------------------------------------------------------------------
function Send_Stranded_Ship_To_Roam returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  wp_count:                  long
  wp_id:                     long
  self_destruct:             boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Destroy bases
  if Sys_Is_Space_Object_Base(ship_id) then
    set self_destruct := TRUE
    set orders_given := TRUE
  endif

  // Can the system be surveyed?
   if Sys_Does_System_Have_Unexplored_Sectors(sys_long_Player_ID, ship_sys_loc) then
     set orders_given := Sys_Give_Space_Object_Order_Survey(ship_id, ship_sys_loc)
   endif

  // Can the ship explore?
  if (not orders_given) then
    set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, ship_sys_loc)
    // Go through a warp point at random
    if (wp_count > 0) then
      set wp_id := Sys_Get_Random_Long(1, wp_count)
      set orders_given := Sys_Give_Space_Object_Order_Warp(ship_id, wp_id)
    endif
  endif

  // Have our ship self-destruct if there's nothing it can do
  if (not orders_given) or (self_destruct) then
    set orders_given := Sys_Give_Space_Object_Order_Any(ship_id, ORDER_SELF_DESTRUCT, ship_sys_loc, ship_sect_loc, 0)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Clear_Minefield
//------------------------------------------------------------------------
function Send_Ship_To_Clear_Minefield returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  target_sys_loc:            long
  target_sect_loc:           long
  target_count:              long
  list_count:                long
  list_index:                long
begin

  // Get our ship's location details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Is there an empty minefield we need to clear (due to marked minefield issue where toggle doesn't clear after first sweep)
  set list_count := lst_AI_Marked_Minefield_Sys.count()
  // Check for zero mine minefields that we can use "attack move" to clear
  if (list_count > 0) then
    set list_index := lst_AI_Marked_Minefield_Sys.indexof(ship_sys_loc)
    // If we are in the same system as the empty minefield then we should "clear" it
    if (list_index > 0) then
      set target_sys_loc := lst_AI_Marked_Minefield_Sys.get(list_index)
      set target_sect_loc := lst_AI_Marked_Minefield_Sect.get(list_index)
      set target_count := lst_AI_Marked_Minefield_Count.get(list_index)
      // Make sure it has no mines!
      if (target_count = 0) then
        // Note should add protection to avoid attacking strong force
        // Use "Attack Move" order to force the fleet into the marked minefield
        set orders_given := Sys_Give_Space_Object_Order_Attack_Move(ship_id, target_sys_loc, target_sect_loc)
        // Remove the location
        call lst_AI_Marked_Minefield_Sys.delete(list_index)
        call lst_AI_Marked_Minefield_Sect.delete(list_index)
        call lst_AI_Marked_Minefield_Count.delete(list_index)
        // Debug output
        call Sys_Debug_Print("Ships", "  - Ordered to clear marked minefield in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Send_Ship_To_Attack
//------------------------------------------------------------------------
function Send_Ship_To_Attack returns boolean
params
  ship_id:                   long
  unit_group:                boolean
vars
  orders_given:              boolean := FALSE
  skip_attack:               boolean := FALSE
  list_count:                long
  design_type:               string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_movement:             long
  ship_attack_dist:          long
  ship_obj_type:             long
  ship_strength:             long
  ship_supply:               long
  ship_ordnance:             long
  ship_max_ordnance:         long
  target_dist:               long
  target_found:              long
  target_loc_type:           long
  target_index:              long
  target_obj_id:             long
  target_sys_loc:            long
  target_sect_loc:           long
  target_name:               string
  same_sys_only:             boolean := FALSE
  single_target_only:        boolean := FALSE
  min_dist:                  long
  list_index:                long
  found_sys_loc:             long
  found_sect_loc:            long
  found_index:               long
begin

  // Get our ship's details
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set design_type := Get_General_AI_Design_Type(design_type)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_strength := Calculate_Space_Object_Strength(ship_id)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_attack_dist := ship_movement + Sys_Get_Random_Long(0, Sys_Divide_Long(ship_movement, 3))
  set ship_obj_type := Sys_Get_Space_Object_Type(ship_id)
  set ship_supply := Sys_Get_Space_Object_Current_Supply(ship_id)
  set ship_ordnance := Sys_Get_Space_Object_Current_Ordnance(ship_id)
  set ship_max_ordnance := Sys_Get_Space_Object_Maximum_Ordnance(ship_id)

  // Clear our previous target lists
  call gbl_lst_target_loc_type.clear()
  call gbl_lst_target_index.clear()
  call gbl_lst_target_obj_id.clear()
  call gbl_lst_target_sys_loc.clear()
  call gbl_lst_target_sect_loc.clear()

  // Don't attack if we are low on supplies or ordnance
  if (unit_group) then
    set skip_attack := (ship_supply < 500) or (ship_ordnance < ship_max_ordnance * 0.25)
    set ship_strength := ship_strength * 2
    // Drone groups can attack targets at distance
    if Get_Unit_Group_Type(ship_id) = "Drone" then
      set ship_attack_dist := ship_movement + Sys_Get_Random_Long(0, lng_AI_Categorization * 20)
    endif
    // Fighter groups should only attack targets in the same system
    if Get_Unit_Group_Type(ship_id) = "Fighter" then
      set same_sys_only := TRUE
    endif
  else
    set skip_attack := (ship_supply < 1000) or (ship_ordnance < ship_max_ordnance * 0.25)
  endif

  // Certain design types should attack only in system
  if design_type = "Ship (Attack)" or design_type = "Ship (Attack Base)" or design_type = "Ship (Defense)" or design_type = "Ship (Seeker)" or design_type = "Ship (Scout)" then
    set same_sys_only := TRUE
  endif

  // Patrol Ships can attack nearby systems but only targets that have a total count of 1
  if design_type = "Ship (Patrol)" then
    set single_target_only := TRUE
    set ship_attack_dist := ship_movement * Sys_Get_Random_Long(1, 3)
  endif

  // Adjust the attack range if we're on the AI team
  if bool_AI_Team_Mode_On then
    set ship_attack_dist := ship_attack_dist * 2
  endif

  if (not skip_attack) then
    // Debug output
    call Sys_Debug_Print("Ships", "    - Strength = " + Sys_Convert_Long_To_String(ship_strength))

    // Priority #1 - Defense Locations (Enemy ships/colonies in our colony systems)
    set list_count := lst_AI_Defense_Location_System.count()
    // Pick a defense location target to attack (only within the ship's movement range)
    if (list_count > 0) then
      set target_found := Get_Target_To_Attack(LOCATION_TYPE_DEFENSE, 1, ship_sys_loc, ship_sect_loc, ship_movement, ship_strength, SPACE_OBJECT_TYPE_SHIP, 0, ship_movement, FALSE, FALSE, FALSE, same_sys_only, single_target_only)
    endif

    // Priority #2 - Nearby Enemy Locations
    if (target_found = 0) then
      set list_count := lst_AI_Nearby_Enemy_Location_System.count()
      // Pick a nearby enemy location target to attack
      if (list_count > 0) then
        set target_found := Get_Target_To_Attack(LOCATION_TYPE_NEARBY_ENEMY, 1, ship_sys_loc, ship_sect_loc, ship_movement, ship_strength, SPACE_OBJECT_TYPE_SHIP, 0, ship_attack_dist, FALSE, FALSE, FALSE, same_sys_only, single_target_only)
      endif
    endif

    // Priority #3 - Attack Locations
    if (target_found = 0) then
      set list_count := lst_AI_Attack_Location_System.count()
      // Pick an attack location target to attack
      if (list_count > 0) then
        set target_found := Get_Target_To_Attack(LOCATION_TYPE_ATTACK, 1, ship_sys_loc, ship_sect_loc, ship_movement, ship_strength, SPACE_OBJECT_TYPE_SHIP, 0, ship_attack_dist, FALSE, FALSE, FALSE, same_sys_only, single_target_only)
      endif
    endif

    // Priority #4 - Follow up Request
    if (target_found = 0) then
      set list_count := lst_AI_Request_Location_System.count()
      // Find a colony in a system where a request was made
      if (list_count > 0) then
        for list_index := 1 to list_count do
          set target_sys_loc := lst_AI_Request_Location_System.get(list_index)
          set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
          set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, target_sys_loc, target_sect_loc)
          set min_dist := 20
          // Is this request location closer than the previous ones?
          if (target_dist < min_dist) then
            set min_dist := target_dist
            set found_sys_loc := target_sys_loc
            set found_sect_loc := target_sect_loc
            set found_index := list_index
          endif
        endfor
        // Order our ship to a colony in the demand request system
        if (found_sys_loc > 0) then
          set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, found_sys_loc, found_sect_loc)
          // Remove the request system to visit to avoid duplicate orders
          call lst_AI_Request_Location_System.delete(found_index)
          // Debug output
          call Sys_Debug_Print("Ships","    - Ordered to support request in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
        endif
      endif
    endif

    // Did we find a target for our ship?
    if (target_found > 0) then
      set target_loc_type := gbl_lst_target_loc_type.get(1)
      set target_index := gbl_lst_target_index.get(1)
      set target_obj_id := gbl_lst_target_obj_id.get(1)
      set target_sys_loc := gbl_lst_target_sys_loc.get(1)
      set target_sect_loc := gbl_lst_target_sect_loc.get(1)
      // Give our ship the order to attack
      if (sys_bool_Is_Simultaneous_Game) then
        set orders_given := Sys_Give_Space_Object_Order_Attack_Seek(ship_id, target_obj_id)
      else
        set orders_given := Sys_Give_Space_Object_Order_Attack_Move(ship_id, target_sys_loc, target_sect_loc)
      endif
      // Remove the location
      call remove_location(target_loc_type, target_index) then
      call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_ATTACK)
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Ship_Order_Load_Cargo
//------------------------------------------------------------------------
function Ship_Order_Load_Cargo returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
  second_pickup:             boolean
vars
  orders_given:              boolean := FALSE
  list_count:                long
  list_index:                long
  cargo_pickup_count:        long
  cargo_pickup_index:        long
  planet_id:                 long
  planet_cargo:              long
  planet_sys_loc:            long
  planet_sect_loc:           long
  planet_name:               string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_max_cargo:            long
  ship_cargo_amt:            long
  move_sys_loc:              long
  move_sect_loc:             long
  move_planet_id:            long
  move_planet_cargo:         long
  move_planet_dist:          long
  pickup_pts:                long
  pickup_dist:               long
  pickup_max_pts:            long := -999999
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_max_cargo := Sys_Get_Space_Object_Cargo_Total_Space(ship_id)
  set ship_cargo_amt := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, cargo_type, cargo_unit_type)
  set gbl_ship_cargo_amt_to_load := 0

  // CARGO_ITEM_TYPE_UNIT: Drone, Fighter, Troop, Satellite, Mine, Weapon Platform
  // CARGO_ITEM_TYPE_POPULATION: Population

  // Select one of our planets that is nearby and has the wanted cargo item
  set list_count := lst_AI_Our_Colonies.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      set planet_id := lst_AI_Our_Colonies.get(list_index)
      set planet_cargo := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(planet_id, cargo_type, cargo_unit_type)
      // If the planet has the desired cargo, determine the pick up value for our transport
      if (planet_cargo > 0) then
        set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
        set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
        // Check for enemies
        if (not Is_Enemy_Present_In_Sector(planet_sys_loc, planet_sect_loc)) then
          // Calculate the pick up value
          set pickup_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
          set pickup_pts :=  planet_cargo - (pickup_dist * 50)

          // Add extra value for unit hubs
          if (lst_AI_Our_Colony_Unit_Hubs.indexof(planet_id) > 0) then
            set pickup_pts := pickup_pts + 1000
          endif

          // Add extra pick up value for colonies that have a lot more units then they should
          case cargo_unit_type
            "Troop":
              if (lst_AI_Colony_High_Troops.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 500
              else
                set pickup_pts := pickup_pts - 500
              endif
            "Fighter":
              if (lst_AI_Colony_High_Fighters.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 500
              endif
            "Weapon Platform":
              if (lst_AI_Colony_High_Weapon_Platforms.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 2000
              else
                set pickup_pts := pickup_pts - 2000
              endif
            "Satellite":
              if (lst_AI_Colony_High_Satellites.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 1000
              else
                set pickup_pts := pickup_pts - 1000
              endif
            "Mine":
              if (lst_AI_Colony_High_Mines.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 100
              else
                set pickup_pts := pickup_pts - 100
              endif
            "Drone":
              if (lst_AI_Colony_High_Drones.indexof(planet_id) > 0) then
                set pickup_pts := pickup_pts + 1000
              else
                set pickup_pts := pickup_pts - 1000
              endif
          endcase

          // Check the pickup cargo lists to avoid giving two ships the same pickup order in the same turn
          set cargo_pickup_count := gbl_lst_cargo_loc_id.count()

          if (cargo_pickup_count > 0) then
            for cargo_pickup_index := 1 to cargo_pickup_count do
              if (gbl_lst_cargo_loc_id.get(cargo_pickup_index) = planet_id) then
                if (gbl_lst_cargo_type.get(cargo_pickup_index) = cargo_unit_type) then
                  set pickup_pts := -999999
                endif
              endif
            endfor
          endif

          // Choose the planet that offers the best compromise between distance and cargo
          if (pickup_pts > pickup_max_pts) then
            set pickup_max_pts := pickup_pts
            set move_sys_loc := planet_sys_loc
            set move_sect_loc := planet_sect_loc
            set move_planet_id := planet_id
            set move_planet_cargo := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(move_planet_id, cargo_type, cargo_unit_type)
            set move_planet_dist := pickup_dist
            set planet_name := Sys_Get_Space_Object_Name(planet_id)
          endif
        endif
      endif
    endfor
  endif

  // Order our ship to pick up the units
  if (move_sys_loc > 0) then
    set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
    set orders_given := Sys_Give_Space_Object_Order_Load_All_Cargo(ship_id, cargo_type, cargo_unit_type, move_planet_id)
    set gbl_ship_cargo_amt_to_load := Sys_Min_Long(ship_cargo_amt + move_planet_cargo, ship_max_cargo)
    // Track location to avoid giving multiple orders
    call gbl_lst_cargo_loc_id.add(move_planet_id)
    call gbl_lst_cargo_type.add(cargo_unit_type)
    call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_LOAD_CARGO)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to pick up " + cargo_unit_type + "(s) from " + planet_name + " (" + Sys_Convert_Long_To_String(move_planet_dist) + ")")
  endif

  // If the load order will give our ship more than 80% capacity of units, add a launch order to maximize its movement
  if (orders_given) then
    if (not second_pickup) then
      if ((cargo_unit_type = "Mine") or (cargo_unit_type = "Satellite")) and (gbl_ship_cargo_amt_to_load > (ship_max_cargo * 0.8)) then
        call Ship_Order_Launch_Units(ship_id, cargo_type, cargo_unit_type)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Ship_Order_Drop_Cargo
//------------------------------------------------------------------------
function Ship_Order_Drop_Cargo returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_cargo_amt:            long
  ship_movement:             long
  ship_movement_left:        long
  list_count:                long
  list_index:                long
  planet_id:                 long
  planet_sys_loc:            long
  planet_sect_loc:           long
  planet_dist:               long
  planet_unit_count:         long
  planet_space_left:         long
  drop_pts:                  long
  drop_min_pts:              long := 999999
  drop_target_id:            long
  drop_sys_loc:              long
  drop_sect_loc:             long
  drop_dist:                 long
  drop_name:                 string
  low_on_units:              boolean := FALSE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_cargo_amt := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, cargo_type, cargo_unit_type)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)

  // Go through our list of colonies and determine the colony that needs the cargo the most
  set list_count := lst_AI_Our_Colonies.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      set planet_id := lst_AI_Our_Colonies.get(list_index)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
      set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      set planet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, planet_sys_loc, planet_sect_loc)
      set planet_unit_count := Sys_Get_Space_Object_Cargo_Item_Type_Count(planet_id, CARGO_ITEM_TYPE_UNIT, cargo_unit_type)
      set planet_space_left := Sys_Get_Space_Object_Cargo_Space_Remaining(planet_id)

      // Modifiers for cargo type
      case cargo_unit_type
        "Troop":
          if (lst_AI_Colony_Low_Troops.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
        "Fighter":
          if (lst_AI_Colony_Low_Fighters.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
        "Weapon Platform":
          if (lst_AI_Colony_Low_Weapon_Platforms.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
        "Satellite":
          if (lst_AI_Colony_Low_Satellites.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
        "Mine":
          if (lst_AI_Colony_Low_Mines.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
        "Drone":
          if (lst_AI_Colony_Low_Drones.indexof(planet_id) > 0) then
            set low_on_units := TRUE
          endif
      endcase

      // Prioritize planets in defense/border locations or low on the carried unit
      if (lst_AI_Defense_Location_System.indexof(planet_sys_loc) > 0) or (lst_AI_Border_System.indexof(planet_sys_loc) > 0) or (low_on_units) then
        set drop_pts := drop_pts + (planet_unit_count + planet_dist)
      else
        set drop_pts := drop_pts + (5 * planet_unit_count + planet_dist)
      endif

      // Don't pick planets with an enemy presence
      if Is_Enemy_Present_In_Sector(planet_sys_loc, planet_sect_loc) then
        set drop_pts := 999999
      endif

      // Choose the planet with the lowest drop points amount
      if (drop_pts < drop_min_pts) and (ship_cargo_amt < planet_space_left) then
        set drop_min_pts := drop_pts
        set drop_target_id := planet_id
        set drop_sys_loc := planet_sys_loc
        set drop_sect_loc := planet_sect_loc
        set drop_dist := planet_dist
        set drop_name := Sys_Get_Space_Object_Name(planet_id)
      endif
    endfor
  endif

  // Order our ship to move to the planet and drop off its cargo
  if (drop_target_id > 0) then
    // Give our ship the order to drop its cargo at the target planet
    set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, drop_sys_loc, drop_sect_loc)
    set orders_given := Sys_Give_Space_Object_Order_Drop_All_Cargo(ship_id, cargo_type, cargo_unit_type, drop_target_id)
    call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_DROP_CARGO)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to drop " + cargo_unit_type + "(s) for " + drop_name + " (" + Sys_Convert_Long_To_String(drop_dist) + ")")
    // Will our ship have extra movement remaining after the drop off?
    if (ship_movement > 0) and (drop_dist > 0) then
      set ship_movement_left := Sys_Mod_Long(drop_dist, ship_movement)
      // Leftover movement?
      if (ship_movement_left > 0) then
        // Debug output
        call Sys_Debug_Print("Ships", "      - Has " + Sys_Convert_Long_To_String(ship_movement_left) + " movement left after drop off")
        // Attempt to have our ship pick up more of the same units to maximize its movement
        call Ship_Order_Load_Cargo(ship_id, cargo_type, cargo_unit_Type, TRUE)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Ship_Order_Launch_Units
//------------------------------------------------------------------------
function Ship_Order_Launch_Units returns boolean
params
  ship_id:                   long
  cargo_type:                long
  cargo_unit_type:           string
vars
  orders_given:              boolean := FALSE
  list_count:                long
  list_index:                long
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_cargo_count:          long
  ship_cargo_amt:            long
  ship_movement:             long
  ship_movement_left:        long
  wp_sys_loc:                long
  wp_sect_loc:               long
  wp_dest_sys:               long
  move_sys_loc:              long
  move_sect_loc:             long
  move_dist:                 long
  min_dist:                  long := 999999
  this_dist:                 long
  num_units:                 long
  unit_mod:                  long := 1
  enemy_mod:                 long := 0
  system_name:               string
  max_mines:                 long := 1000
  max_satellites:            long := 100
  drop_units:                boolean := TRUE
begin

  // Get our ship's details
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set ship_cargo_amt := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, cargo_type, cargo_unit_type)
  set ship_cargo_count := Sys_Get_Space_Object_Cargo_Item_Type_Count(ship_id, cargo_type, cargo_unit_type)
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)

  // Adjust for potential units that might be picked up
  if (gbl_ship_cargo_amt_to_load > 0) and (ship_cargo_amt > 0) then
    set ship_cargo_count := ship_cargo_count + Sys_Divide_Long(gbl_ship_cargo_amt_to_load, ship_cargo_amt)
  endif

  // Drop mines or satellites at our closest drop location considering the current units present
  if (cargo_unit_type = "Mine") or (cargo_unit_type = "Satellite") then
    set list_count := lst_AI_Unit_Drop_Location_System.count()
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set wp_sys_loc := lst_AI_Unit_Drop_Location_System.get(list_index)
        set wp_sect_loc := lst_AI_Unit_Drop_Location_Sector.get(list_index)
        set wp_dest_sys := lst_AI_Unit_Drop_Location_Dest_Sys.get(list_index)
        set enemy_mod := 0

        // How many units do we have at that location? Does it exceed the max units per sector?
        set num_units := Sys_Get_Number_Of_Units_In_Space_Sector(sys_long_Player_ID, cargo_unit_type, wp_sys_loc, wp_sect_loc)

        if (cargo_unit_type = "Mine") then
          set unit_mod := 10
          // Don't drop more mines than can be dropped in a sector
          if (num_units + ship_cargo_count > max_mines) then
            set drop_units := FALSE
          endif
        endif

        if (cargo_unit_type = "Satellite") then
          set unit_mod := 1
          // Don't drop more satellites than can be dropped in a sector
          if (num_units + ship_cargo_count > max_satellites) then
            set drop_units := FALSE
          endif
        endif

        // Increase priority for warp points that lead to enemies
        if Does_Enemy_Have_Colony_In_System(wp_dest_sys) then
          set enemy_mod := enemy_mod - 25
        endif
        if Is_Enemy_Present_At_Destination_WP(wp_sys_loc, wp_dest_sys) then
          set enemy_mod := enemy_mod - 25
        endif

        // Increase priority for border systems
        if (lst_AI_Border_System.indexof(wp_sys_loc) > 0) then
          set enemy_mod := enemy_mod - 25
        endif

        // Don't drop units if an enemy is in the location
        if Is_Enemy_Present_In_Sector(wp_sys_loc, wp_sect_loc) then
          set drop_units := FALSE
        endif

        // Choose a warp point that is close and needs more units
        if (drop_units) then
          set this_dist := (num_units * unit_mod) - enemy_mod + Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, wp_sys_loc, wp_sect_loc)
          if (this_dist < min_dist) then
            set min_dist := this_dist
            set move_sys_loc := wp_sys_loc
            set move_sect_loc := wp_sect_loc
            set move_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, move_sys_loc, move_sect_loc)
            set system_name := Sys_Get_Solar_System_Name(wp_sys_loc)
          endif
        endif
      endfor
    endif
  endif

  // Order our ship to drop units at selected location
  if (move_sys_loc > 0) then
    set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
    set orders_given := Sys_Give_Space_Object_Order_Launch_All_Units(ship_id, cargo_type, cargo_unit_type)
    call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_LAUNCH)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to launch " + cargo_unit_type + "(s) in " + system_name + " system " + Convert_Sector_To_String(move_sect_loc))
    call Sys_Debug_Print("Ships", "    - Has " + Sys_Convert_Long_To_String(ship_cargo_count) + " " + cargo_unit_type + "s " + "in its cargo")
    call Sys_Debug_Print("Ships", "    - There are " + Sys_Convert_Long_To_String(num_units) + " " + cargo_unit_type + "s " + "in the sector")
    // Will we have leftover movement?
    if (ship_movement > 0) and (move_dist > 0) then
      set ship_movement_left := Sys_Mod_Long(move_dist, ship_movement)
      if (ship_movement_left > 0) then
        // Debug output
        call Sys_Debug_Print("Ships", "      - Has " + Sys_Convert_Long_To_String(ship_movement_left) + " movement left after drop off")
        // Attempt to send our ship to pick up more of the same units immediately
        call Ship_Order_Load_Cargo(ship_id, cargo_type, cargo_unit_Type, TRUE)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Ship_Order_Go_To_Nearest_Colony
//------------------------------------------------------------------------
function Ship_Order_Go_To_Nearest_Colony returns boolean
params
  ship_id:                   long
  curr_system_only:          boolean
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  colony_id:                 long
  colony_name:               string
  colony_sys_loc:            long
  colony_sect_loc:           long
begin

  // Note our ship's name and location
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Locate our nearest colony
  if (not orders_given) then
    set list_count := lst_AI_Our_Colonies.count()

    if (list_count > 0) then
      set colony_id := Find_Nearest_Object_In_List(lst_AI_Our_Colonies, ship_sys_loc, ship_sect_loc, TRUE, curr_system_only)
      set colony_name := Sys_Get_Space_Object_Name(colony_id)
      set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
      set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
      // Order our ship to the colony
      if (colony_sys_loc > 0) then
        set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, colony_sys_loc, colony_sect_loc)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Ordered to our nearest colony on " + colony_name)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Ship_Order_Go_To_SY
//------------------------------------------------------------------------
function Ship_Order_Go_To_SY returns boolean
params
  ship_id:                   long
  clear_orders:              boolean
vars
  orders_given:              boolean := FALSE
  ship_sys_loc:              long
  ship_sect_loc:             long
  list_count:                long
  sobj_id:                   long
  sobj_name:                 string
  sobj_sys_loc:              long
  sobj_sect_loc:             long
begin

  // Note our ship's name and location
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Locate our nearest Space Yard
  if (not orders_given) then
    set list_count := lst_AI_Our_Space_Yards.count()

    if (list_count > 0) then
      set sobj_id := Find_Nearest_Object_In_List(lst_AI_Our_Space_Yards, ship_sys_loc, ship_sect_loc, TRUE, FALSE)
      set sobj_name := Sys_Get_Space_Object_Name(sobj_id)
      set sobj_sys_loc := Sys_Get_Space_Object_System_Location(sobj_id)
      set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)

      // Order our ship to the Space Yard
      if (sobj_sys_loc > 0) then
        if (clear_orders) then
          set orders_given := Sys_Space_Object_Clear_Orders(ship_id)
        endif
        set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, sobj_sys_loc, sobj_sect_loc)
        set gbl_SY_location := sobj_id
        set gbl_SY_sys_loc := sobj_sys_loc
        set gbl_SY_sect_loc := sobj_sect_loc
        // Debug output
        call Sys_Debug_Print("Ships", "    - Ordered to nearest Space Yard at " + sobj_name)
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Order_Go_To_Resupply_Depot
//------------------------------------------------------------------------
function Order_Go_To_Resupply_Depot returns boolean
params
  ship_id:                   long
  fleet_id:                  long
vars
  orders_given:              boolean := FALSE
begin

  // Clear our ship's/fleet's orders first, then send the ship or fleet to a resupply location
  if (ship_id > 0) then
    call Sys_Space_Object_Clear_Orders(ship_id)
    set orders_given := Sys_Give_Space_Object_Order_Resupply_At_Nearest(ship_id)
    call lst_AI_Our_Ships_Status.set(lst_AI_Our_Ships.indexof(ship_id), SHIP_STATUS_RESUPPLY)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to resupply")
  else
    call Sys_Empire_Fleet_Clear_Orders(sys_long_Player_ID, fleet_id)
    set orders_given := Sys_Give_Empire_Fleet_Order_Resupply_At_Nearest(sys_long_Player_ID, fleet_id)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to resupply")
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Order_Go_To_Quell_Riot
//------------------------------------------------------------------------
function Order_Go_To_Quell_Riot returns boolean
params
  ship_id:                   long
  fleet_id:                  long
vars
  orders_given:              boolean := FALSE
  design_type:               string
  planet_id:                 long
  planet_name:               string
  sobj_sys_loc:              long
  sobj_sect_loc:             long
begin

  // Get our ship's details
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Send our ship to the rioting planet
  if (lst_AI_Our_Rioting_Colonies.count() > 0) then
    set planet_id := lst_AI_Our_Rioting_Colonies.get(1)
    set planet_name := Sys_Get_Space_Object_Name(planet_id)
    set sobj_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
    set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)

    if (ship_id > 0) then
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, sobj_sys_loc, sobj_sect_loc)
      // Our Troop Transport should drop troops on the rioting colony
      if (design_type = "Transport (Troop)") then
        call Sys_Give_Space_Object_Order_Drop_All_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Troop", planet_id)
      endif
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to quell riot on " + planet_name)
    else
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, sobj_sys_loc, sobj_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to quell riot on " + planet_name)
    endif
 
    call lst_AI_Our_Rioting_Colonies.delete(1)
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Does_Fleet_Need_Design_Type
//------------------------------------------------------------------------
function Does_Fleet_Need_Design_Type returns boolean
params
  fleet_id:                  long
  fleet_type:                long
  design_type:               string
vars
  lst_fleet_ships:           longlist
  ship_count:                long
  ship_index:                long
  this_ship_id:              long
  this_design_type:          string
  type_count:                long := 0
  needs_design_type:         boolean := FALSE
begin

  // Get a list of ships in our fleet
  call Sys_Get_Empire_Fleet_Ship_List(sys_long_Player_ID, fleet_id, lst_fleet_ships)

  // Check to see if our fleet has the wanted design type
  set ship_count := lst_fleet_ships.count()

  if (ship_count > 0) then
    // Count the number of each design type
    for ship_index := 1 to ship_count do
      set this_ship_id := lst_fleet_ships.get(ship_index)
      set this_design_type := Sys_Get_Space_Object_AI_Design_Type(this_ship_id)
      if (this_design_type = design_type) then
        set type_count := type_count + 1
      endif
    endfor
  endif

  // Does this fleet type require the wanted design type?
  if (fleet_type = FLEET_TYPE_ATTACK) then
    case design_type
      "Carrier (Fighter)":
        if (type_count / ship_count < 0.05) then
          set needs_design_type := TRUE
        endif
      "Carrier (Drone)":
        if (type_count / ship_count < 0.02) then
          set needs_design_type := TRUE
        endif
      "Transport (Troop)":
        if (type_count / ship_count < 0.04) then
          set needs_design_type := TRUE
        endif
      "Transport (Supply)":
        if (type_count / ship_count < 0.04) then
          set needs_design_type := TRUE
        endif
      "Ship (Repair)":
        if (type_count / ship_count < 0.04) then
          set needs_design_type := TRUE
        endif
      "Ship (Mine Sweeper)":
        if (type_count / ship_count < 0.08) then
          set needs_design_type := TRUE
        endif
    endcase
  else
    case design_type
      "Carrier (Fighter)":
        if (type_count / ship_count < 0.05) then
          set needs_design_type := TRUE
        endif
      "Carrier (Drone)":
        if (type_count / ship_count < 0.02) then
          set needs_design_type := TRUE
        endif
      "Ship (Repair)":
        if (type_count / ship_count < 0.04) then
          set needs_design_type := TRUE
        endif
      "Ship (Mine Sweeper)":
        if (type_count / ship_count < 0.08) then
          set needs_design_type := TRUE
        endif
    endcase
  endif

  return needs_design_type
end

//------------------------------------------------------------------------
// Send_Ship_To_Join_Fleet
//------------------------------------------------------------------------
function Send_Ship_To_Join_Fleet returns boolean
params
  ship_id:                   long
vars
  orders_given:              boolean := FALSE
  fleet_selected:            boolean := FALSE
  fleet_count:               long
  fleet_index:               long
  fleet_id:                  long
  fleet_type:                long
  fleet_name:                string
  fleet_dist:                long
  move_sys_loc:              long := 0
  move_sect_loc:             long := 0
  move_to_fleet_id:          long := 0
  move_to_fleet_ship_count:  long := 0
  move_to_fleet_join_count:  long := 0
  move_to_planet_id:         long := 0
  fleet_sys_loc:             long
  fleet_sect_loc:            long
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_movement:             long
  fleet_ship_count:          long
  fleet_ships_wanted:        long
  fleet_ships_joining:       long
  fleet_ships_needed:        long
  task_force_id:             long := 0
  task_force_id_min:         long := 1
  task_force_id_max:         long := 1
  tf_attack:                 long := 1
  tf_defense:                long := 2
  tf_seeker:                 long := 3
  task_force_ship_target:    long := 15
  task_force_count:          long
  task_force_role:           long
  design_type:               string
  join_pts:                  long
  max_join_pts:              long := -999999
  this_pos:                  long
begin

  // Get our ship's details
  set ship_movement := Sys_Max_Long(Sys_Get_Space_Object_Maximum_Movement(ship_id), 1)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
  set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)

  // Debug output
  call Sys_Debug_Print("Ships", "      - Join Fleet:")

  // Determine which fleet our ship should join
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)

  if (fleet_count > 0) then
    for fleet_index := 1 to fleet_count do
      set join_pts := 0
      set fleet_id := Sys_Get_Empire_Fleet_ID(sys_long_Player_ID, fleet_index)
      set fleet_name := "Fleet " + Sys_Convert_Long_To_String(fleet_id)
      set fleet_type := lst_AI_Fleet_Type.get(fleet_index)
      set fleet_sys_loc := Sys_Get_Empire_Fleet_System_Location(sys_long_Player_ID, fleet_id)
      set fleet_sect_loc := Sys_Get_Empire_Fleet_Sector_Location(sys_long_Player_ID, fleet_id)
      set fleet_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, fleet_sys_loc, fleet_sect_loc)
      set fleet_ship_count := Sys_Get_Empire_Fleet_Ship_Count(sys_long_Player_ID, fleet_id)

      // How many ships per fleet?
      if (fleet_type = FLEET_TYPE_ATTACK) then
        if (lng_Pct_Fleets_For_Attack > 0) then
          set fleet_ships_wanted := Sys_Divide_Long((lng_AI_Available_Fleet_Ships_Count * lng_Pct_Ships_For_Attack_Fleets), (fleet_count * lng_Pct_Fleets_For_Attack))
        endif
      else
        if (lng_Pct_Fleets_For_Defense > 0) then
          set fleet_ships_wanted := Sys_Divide_Long((lng_AI_Available_Fleet_Ships_Count * lng_Pct_Ships_For_Defense_Fleets), (fleet_count * lng_Pct_Fleets_For_Defense))
        endif
      endif

      set fleet_ships_joining := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_JOIN_FLEET, 0, 0, fleet_id)
      set fleet_ships_needed := fleet_ships_wanted - fleet_ship_count - fleet_ships_joining

      // Add more points for fleets waiting for ships and are close
      if Sys_Is_Empire_Fleet_Waiting_For_Ships(sys_long_Player_ID, fleet_id) then
        set join_pts := join_pts + 200 - (Sys_Divide_Long(fleet_dist, ship_movement + 1) * 50)
        // Bonus points if in the same system
        if (ship_sys_loc = fleet_sys_loc) then
          set join_pts := join_pts + 500
        endif
      else
        set join_pts := join_pts - (Sys_Divide_Long(fleet_dist, ship_movement + 1) * 50)
      endif
      // Add points for fleets that need our ship's design type
      if Does_Fleet_Need_Design_Type(fleet_id, fleet_type, design_type) then
        set join_pts := join_pts + 200
      endif
      // Add points for fleets that need more ships
      if (fleet_ships_needed > 0) then
        set join_pts := join_pts + Sys_Min_Long(fleet_ships_needed * 25, 250)
      else
        set join_pts := join_pts - 200
      endif
      // Direct Mine Sweepers to our main fleet until we have 3 or more fleets
      if (fleet_id = 1) and (fleet_count < 3) and (design_type = "Ship (Mine Sweeper)") then
        set join_pts := join_pts + 1000
      endif
      // Direct additional Patrol and Boarding Ships to defense fleets
      if (fleet_type = FLEET_TYPE_DEFENSE) then
        if (design_type = "Ship (Patrol)") or (design_type = "Ship (Boarding)") then
          set join_pts := join_pts + 500
        endif
      endif
      // Identify the most appropriate fleet for our ship to join
      if (join_pts > max_join_pts) and (join_pts > 0) then
        set max_join_pts := join_pts
        set move_sys_loc := fleet_sys_loc
        set move_sect_loc := fleet_sect_loc
        set move_to_fleet_id := fleet_id
        set move_to_fleet_ship_count := fleet_ship_count
        set move_to_fleet_join_count := fleet_ships_joining
      endif
      // Debug output
      call Sys_Debug_Print("Ships", "        - Join points " + fleet_name + " = " + Sys_Convert_Long_To_String(join_pts) + " (" + Sys_Convert_Long_To_String(fleet_ships_needed) + ")")
    endfor
  else
    // Debug output
    call Sys_Debug_Print("Ships", "    - No fleets to join")
  endif

  // Order our ship to join the fleet and a specific task force
  if (move_sys_loc > 0) then
    set this_pos := lst_AI_Design_Type_Name.indexof(design_type)
    set task_force_role := lst_AI_Design_Type_Task_Force_Role.get(this_pos)
    set design_type := Get_General_AI_Design_Type(design_type)
    set fleet_name := "Fleet " + Sys_Convert_Long_To_String(move_to_fleet_id)

    // Adjust task force ship targets based on the number of potential fleet ships
    if ((move_to_fleet_ship_count + move_to_fleet_join_count) > 90) then
      set task_force_ship_target := 40
    else
      if ((move_to_fleet_ship_count + move_to_fleet_join_count) > 45) then
        set task_force_ship_target := 25
      endif
    endif

    // AI Task Force Designations
    // 1 - Attack, Defense, Seeker, PD ships
    // 2 - Attack, Defense, Seeker, PD ships
    // 3 - Attack, Defense, Seeker, PD Ships, Specialty Combat Ships (Kamikaze, Boarding, Bombardment)
    // 4 - Carriers
    // 5 - Support Ships

    // Primary Combat Ships
    if (design_type = "Ship (Attack)") or (design_type = "Ship (Defense)") or (design_type = "Ship (Seeker)") then
      case lng_TF_Fill_Strategy
        // Fill up each combat task force sequentially
        AI_TASK_FORCE_FILL_SEQUENTIAL:
          // If task force 1 is near full, open up task force 2
          if Get_Task_Force_Ship_Count(move_to_fleet_id, 1) > task_force_ship_target then) then
            // If task force 2 is near full, open up task force 3
            if Get_Task_Force_Ship_Count(move_to_fleet_id, 2) > task_force_ship_target then) then
              // Join task force 3
              set task_force_id_max := 3
            else
              // Join task force 2
              set task_force_id_max := 2
            endif
          else
            // Send to task force 1
            set task_force_id_max := 1
          endif
        // Focus on filling task force 1
        AI_TASK_FORCE_FILL_CONCENTRATED:
          if (Get_Task_Force_Ship_Count(move_to_fleet_id, 1) < 50) then
            set task_force_id_max := 1
          else
            set task_force_id_max := 2
          endif
        // Concentrate on filling task forces 1&2 and ignore task force 3
        AI_TASK_FORCE_FILL_SPREAD_TWO:
          // Split combat ships between task forces 1&2 based on the number of fleet ships
          if Get_Task_Force_Ship_Count(move_to_fleet_id, 1) > Get_Task_Force_Ship_Count(move_to_fleet_id, 2) then
            set task_force_id_max := 2
          else
            set task_force_id_max := 1
          endif
        // Concentrate on filling task forces 1&2 but then open up task force 3 once 1&2 are mostly full
        AI_TASK_FORCE_FILL_SPREAD_THREE:
          // Split combat ships across offensive task forces based on the number of fleet ships
          if Get_Task_Force_Ship_Count(move_to_fleet_id, 1) > Get_Task_Force_Ship_Count(move_to_fleet_id, 2) then
            if ((move_to_fleet_ship_count + move_to_fleet_join_count) > 30) then
              // Open up Task Force 3 if we have more than 30 fleet ships
              set task_force_id_max := 3
            else
              if ((move_to_fleet_ship_count + move_to_fleet_join_count) > 10) then
                // Open up Task Force 2 if we have more than 10 fleet ships
                set task_force_id_max := 2
              else
                set task_force_id_max := 1
              endif
            endif
          endif
        // Assign specific ship types to specific task forces
        AI_TASK_FORCE_FILL_BY_TYPE:
          case design_type
            "Ship (Attack)":
              set task_force_id_min := 2
              set task_force_id_max := 2
            "Ship (Defense)":
              set task_force_id_min := 3
              set task_force_id_max := 3
            "Ship (Seeker)":
              set task_force_id_min := 1
              set task_force_id_max := 1
          endcase
      endcase
      // Assign task force
      set task_force_id := Sys_Get_Random_Long(task_force_id_min, task_force_id_max)
    endif

    // What is the maximum task force a PD Ship or Attack Base can join? 
    if Get_Task_Force_Ship_Count(move_to_fleet_id, 3) > 0 then
      set task_force_id_max := 3
    else
      if Get_Task_Force_Ship_Count(move_to_fleet_id, 2) > 0 then
        set task_force_id_max := 2
      else
        set task_force_id_max := 1
      endif
    endif

    // For non-primary combat ships
    case design_type
      "Transport (Troop)":
        set task_force_id := 1
      "Ship (Attack Base)":
        set task_force_id := Sys_Get_Random_Long(1, task_force_id_max)
      "Ship (Point-Defense)":
        set task_force_id := Sys_Get_Random_Long(1, task_force_id_max)
      "Ship (Boarding)":
        set task_force_id := 3
      "Ship (Bombardment)":
        set task_force_id := 3
      "Ship (Plague)":
        set task_force_id := 3
      "Ship (Kamikaze)":
        set task_force_id := 3
      "Carrier (Fighter)":
        set task_force_id := 4
      "Carrier (Drone)":
        set task_force_id := 4
      "Transport (Supply)": 
        set task_force_id := 5
      "Ship (Repair)":
        set task_force_id := 5
      "Ship (Mine Sweeper)":
        set task_force_id := 5
    endcase

    // Note task force roles have be condensed to "core" only due to SE5 placement issues

    // Order our ship to join the fleet
    set orders_given := Sys_Give_Space_Object_Order_Join_Fleet(ship_id, move_to_fleet_id, task_force_id, task_force_role)
    // Debug output
    call Sys_Debug_Print("Ships", "    - Ordered to join " + fleet_name + " in task force " + Sys_Convert_Long_To_String(task_force_id))
  else
    // If there are no good fleets to join, go to the nearest Space Yard Hub
    set move_to_planet_id := Find_Nearest_Object_In_List(lst_AI_Our_Space_Yard_Hubs, ship_sys_loc, ship_sect_loc, FALSE, FALSE)
    set move_sys_loc := Sys_Get_Space_Object_System_Location(move_to_planet_id)
    set move_sect_loc := Sys_Get_Space_Object_Sector_Location(move_to_planet_id)
    // Order our ship to move
    if (move_to_planet_id > 0) then
      set orders_given := Sys_Give_Space_Object_Order_Moveto(ship_id, move_sys_loc, move_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Ordered to nearest Space Yard Hub at " + Sys_Get_Space_Object_Name(move_to_planet_id))
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Load_Fleet_Data
//------------------------------------------------------------------------
function Load_Fleet_Data returns boolean
vars
  current_fleet_count:       long
  current_fleet_leader:      long
  lst_current_fleet_leader:  longlist
  prev_fleet_count:          long
  prev_fleet_leader:         long
  lst_prev_fleet_leader:     longlist
  next_fleet_leader:         long
  lost_fleet_count:          long
  lst_lost_fleets:           longlist
  fleet_index:               long
  fleet_type:                long
  fleet_status:              long
  fleet_leader:              long
  storage_index:             long
begin

  // Note the number of fleets we have
  set current_fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)
  set prev_fleet_count := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 1, 7)

  // Have we lost a fleet during the movement phase of the previous turn?
  if (current_fleet_count <> prev_fleet_count) then
    // Make a list of our current fleet leaders
    if (current_fleet_count > 0) then
      for fleet_index := 1 to current_fleet_count do
        call lst_current_fleet_leader.add(Sys_Get_Empire_Fleet_Leader(sys_long_Player_ID, fleet_index))
      endfor
    endif
    // Make a list of our previous turn's fleet leaders
    if (prev_fleet_count > 0) then
      for fleet_index := 1 to prev_fleet_count do
        call lst_prev_fleet_leader.add(Sys_Get_AI_Storage_Long(sys_long_Player_ID, 5, fleet_index * 3))
      endfor
    endif
    // Compare our list of current fleet leaders versus previous fleet leaders to determine which fleet was potentially lost
    if (prev_fleet_count > 0) and (current_fleet_count > 0) then
      for fleet_index := 1 to current_fleet_count do
        set current_fleet_leader := lst_current_fleet_leader.get(fleet_index)
        set prev_fleet_leader := lst_prev_fleet_leader.get(fleet_index + lost_fleet_count)
        set next_fleet_leader := lst_prev_fleet_leader.get(fleet_index + lost_fleet_count + 1)
        // If the current leader doesn't match the previous one, then one of our fleets were lost
        if (current_fleet_leader <> prev_fleet_leader) then
          if (current_fleet_leader = next_fleet_leader) then
            set lost_fleet_count := lost_fleet_count + 1
            call lst_lost_fleets.add(fleet_index)
            // Debut output
            call Sys_Debug_Print("Ships", "  - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " lost!")
          endif
        endif
      endfor
    endif
  endif

  // Load our fleet data
  if (prev_fleet_count > 0) then
    // Debug output
    call Sys_Debug_Print("Ships", "  - Load Fleet Data:")
    for fleet_index := 1 to current_fleet_count do
      set storage_index := (fleet_index - 1) * 3
      // Skip fleets that were lost
      if (lst_lost_fleets.indexof(fleet_index) < 1) then
        set fleet_type := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 1)
        set fleet_status := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 2)
        set fleet_leader := Sys_Get_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 3)
        // Temp bug fix
        if (fleet_type <> FLEET_TYPE_ATTACK) or (fleet_type <> FLEET_TYPE_DEFENSE) then
          set fleet_type := Sys_Get_Random_Long(1, 2)
        endif
        // Update our fleet lists
        call lst_AI_Fleet_Type.add(fleet_type)
        call lst_AI_Fleet_Status.add(fleet_status)
        call lst_AI_Fleet_Leader.add(fleet_leader)
        call lst_AI_Fleet_Sys_Loc.add(0)
        call lst_AI_Fleet_Sect_Loc.add(0)
        call lst_AI_Fleet_Strength.add(0)
        call lst_AI_Fleet_Movement.add(0)
        call lst_AI_Fleet_Range.add(0)
        call lst_AI_Fleet_Mine_Sweep_Count.add(0)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Type = " + Sys_Convert_Long_To_String(fleet_type))
        call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Status = " + Sys_Convert_Long_To_String(fleet_status))
        call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Leader = " + Sys_Get_Space_Object_Name(fleet_leader))
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Save_Fleet_Data
//------------------------------------------------------------------------
function Save_Fleet_Data returns boolean
vars
  fleet_count:               long
  fleet_index:               long
  fleet_type:                long
  fleet_status:              long
  fleet_leader:              long
  storage_index:             long
begin

  // Save our fleet type to memory
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)
  call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 1, 7, fleet_count)

  if (fleet_Count > 0) then
    // Debug output
    call Sys_Debug_Print("Ships", "  - Save Fleet Data:")
    for fleet_index := 1 to fleet_count do
      set storage_index := (fleet_index - 1) * 3
      set fleet_type := lst_AI_Fleet_Type.get(fleet_index)
      set fleet_status := lst_AI_Fleet_Status.get(fleet_index)
      set fleet_leader := lst_AI_Fleet_Leader.get(fleet_index)
      // Debug output
      call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Type = " + Sys_Convert_Long_To_String(fleet_type))
      call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Status = " + Sys_Convert_Long_To_String(fleet_status))
      call Sys_Debug_Print("Ships", "    - Fleet " + Sys_Convert_Long_To_String(fleet_index) + " Leader = " + Sys_Get_Space_Object_Name(fleet_leader))
      // Save our fleet's details
      call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 1, fleet_type)
      call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 2, fleet_status)
      call Sys_Set_AI_Storage_Long(sys_long_Player_ID, 5, storage_index + 3, fleet_leader)
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Get_Fleet_Type_To_Add
//------------------------------------------------------------------------
function Get_Fleet_Type_To_Add returns long
vars
  fleet_count:               long
  fleet_index:               long
  atk_count:                 long
  def_count:                 long
  pct_atk_fleets:            long
  pct_def_fleets:            long
  fleet_to_add:              long := 0
begin

  // Determine how many fleets are dedicated to attack or defense
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)

  if (fleet_count > 0) then
    for fleet_index := 1 to fleet_count do
      if (lst_AI_Fleet_Type.get(fleet_index) = FLEET_TYPE_ATTACK) then
        set atk_count := atk_count + 1
      endif
      if (lst_AI_Fleet_Type.get(fleet_index) = FLEET_TYPE_DEFENSE) then
        set def_count := def_count + 1
      endif
    endfor
  
    // Note our current fleet distribution
    set pct_atk_fleets := Sys_Trunc((atk_count / fleet_count) * 100)
    set pct_def_fleets := Sys_Trunc((def_count / fleet_count) * 100)
  endif

  // Determine the type of fleet to add
  if (lng_Pct_Fleets_For_Attack > pct_atk_fleets) then
    set fleet_to_add := FLEET_TYPE_ATTACK
  else
    set fleet_to_add := FLEET_TYPE_DEFENSE
  endif

  return fleet_to_add
end

//------------------------------------------------------------------------
// Fleet_Orders
//------------------------------------------------------------------------
function Fleet_Orders returns boolean
vars
  num_fleets_wanted:         long
  fleet_count:               long
  fleet_count_alt:           long
  fleet_index:               long
  fleet_index_alt:           long
  fleet_id:                  long
  fleet_type:                long
  fleet_name:                string
  fleets_to_add:             long
  sys_loc:                   long
  sect_loc:                  long
  random_index:              long
  fleet_atk_form:            long
  fleet_def_form:            long
  tf_id:                     long
  tf_name:                   string
  highest_fleet_id:          long := 0
  ship_count:                long
  fleet_size_mod:            real := 1
begin

  // Get the number of fleets we have
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)

  // How many fleets do we want?
  if (lng_AI_Available_Fleet_Ships_Count < 30) then
    set num_fleets_wanted := Sys_Trunc(lng_AI_Available_Fleet_Ships_Count / 10 + 0.99)
  else
    // Determine average fleet size
    case (lng_AI_Fleet_Size)
      FLEET_SIZE_SMALL:
        // ~6 fleets per 100 ships
        set num_fleets_wanted := Sys_Trunc(lng_AI_Available_Fleet_Ships_Count ^ 0.40)
      FLEET_SIZE_MEDIUM:
        // ~5 fleets per 100 ships
        set num_fleets_wanted := Sys_Trunc(lng_AI_Available_Fleet_Ships_Count ^ 0.36)
      FLEET_SIZE_LARGE:
        // ~4 fleets per 100 ships
        set num_fleets_wanted := Sys_Trunc(lng_AI_Available_Fleet_Ships_Count ^ 0.33)
    endcase
  endif

  // If our space combat is poor then adjust fleet sizes to be larger by having fewer fleets
  if (bool_Race_Space_Combat_Poor) then
    if (num_fleets_wanted > 10) then
      set num_fleets_wanted := Sys_Trunc(num_fleets_wanted * 0.8)
    else
      if (num_fleets_wanted > 4) then
        set num_fleets_wanted := num_fleets_wanted - 1
      endif
    endif
  endif

  // If we are losing badly then compile all our ships to a single fleet
  if (lng_AI_Empire_Strategy = AI_EMPIRE_STRATEGY_LAST_STAND) or (lng_AI_Empire_Strategy = AI_EMPIRE_STRATEGY_OUT_IN_FLAMES) then
    set num_fleets_wanted := 1
  endif

  // If we are in team mode, reduce the number of 
  if (Sys_Are_We_Computer_Player(sys_long_player_ID) and Sys_Is_Game_Using_Teams()) then
    if (num_fleets_wanted > 2) then
      set num_fleets_wanted := 1 + Sys_Divide_Long(num_fleets_wanted, 2)
    endif
  endif

  // If we are a neutral empire, keep one fleet
  if (Sys_Are_We_Neutral_Empire(Sys_long_Player_ID)) then
    set num_fleets_wanted := 1
  endif

  // Debug output
  call Sys_Debug_Print("Ships", "  - # Fleets = " + Sys_Convert_Long_To_String(fleet_count))
  call Sys_Debug_Print("Ships", "  - # Fleets Wanted = " + Sys_Convert_Long_To_String(num_fleets_wanted))
  call Sys_Debug_Print("Ships", "  - # Ships for Fleets = " + Sys_Convert_Long_To_String(lng_AI_Available_Fleet_Ships_Count))

  // Make sure each of our fleets has a unique name
  if (fleet_count > 0) then
    for fleet_index := 1 to fleet_count do
      set fleet_id := Sys_Get_Empire_Fleet_ID(sys_long_Player_ID, fleet_index)
      if (fleet_id > highest_fleet_id) then
        set highest_fleet_id := fleet_id
      endif
    endfor
  endif

  // Do we need more fleets?
  set fleets_to_add := num_fleets_wanted - fleet_count

  // Create a new fleet
  if (fleets_to_add > 0) then
    for fleet_index := 1 to fleets_to_add do

      // Set the fleet's initial base
      if (lst_AI_Fleet_Hub_System.count() > 0) then
        set random_index := Sys_Get_Random_Long(1, lst_AI_Fleet_Hub_System.count())
        set sys_loc := lst_AI_Fleet_Hub_System.get(random_index)
        set sect_loc := lst_AI_Fleet_Hub_Sector.get(random_index)
      else
        set sys_loc := Sys_Get_Empire_Home_System(sys_long_Player_ID)
        set sect_loc := Sys_Get_Empire_Home_Sector(sys_long_Player_ID)
      endif

      // What type of fleet should we add?
      set fleet_type := Get_Fleet_Type_To_Add()
      call lst_AI_Fleet_Type.add(fleet_type)
      call lst_AI_Fleet_Status.add(FLEET_STATUS_WAITING_FOR_SHIPS)
      call lst_AI_Fleet_Leader.add(0)
      call lst_AI_Fleet_Sys_Loc.add(0)
      call lst_AI_Fleet_Sect_Loc.add(0)
      call lst_AI_Fleet_Strength.add(0)
      call lst_AI_Fleet_Movement.add(0)
      call lst_AI_Fleet_Range.add(0)
      call lst_AI_Fleet_Mine_Sweep_Count.add(0)

      // Choose our fleet's name and formation
      if (fleet_type = FLEET_TYPE_ATTACK) then
        set fleet_name := Sys_ConCat_String("Fleet ", Sys_Convert_Long_To_String(highest_fleet_id + fleet_index))
        set fleet_atk_form := lng_Atk_Fleet_Atk_Form
        set fleet_def_form := lng_Atk_Fleet_Def_Form
      else
        set fleet_name := Sys_ConCat_String("Fleet ", Sys_Convert_Long_To_String(highest_fleet_id + fleet_index))
        set fleet_atk_form := lng_Def_Fleet_Atk_Form
        set fleet_def_form := lng_Def_Fleet_Def_Form
      endif

      // Create our fleet
      set fleet_id := Sys_Create_Empire_Fleet(sys_long_Player_ID, fleet_name, sys_loc, sect_loc, fleet_atk_form, fleet_def_form)

      // Set up our new fleet's task forces
      // Primary task force
      call Sys_Set_Empire_Fleet_Taskforce_Attack_Strategy(sys_long_Player_ID, fleet_id, 1, lng_Atk_Ship_Atk_Strat)
      call Sys_Set_Empire_Fleet_Taskforce_Defense_Strategy(sys_long_Player_ID, fleet_id, 1, lng_Atk_Ship_Def_Strat)
      call Sys_Set_Empire_Fleet_Taskforce_Attack_Formation(sys_long_Player_ID, fleet_id, 1, lng_TF_Atk_Ship_Atk_Form)
      call Sys_Set_Empire_Fleet_Taskforce_Defense_Formation(sys_long_Player_ID, fleet_id, 1, lng_TF_Atk_Ship_Def_Form)
      // Other task forces
      call Sys_Create_Empire_Fleet_Task_Force(sys_long_Player_ID, fleet_id, "Task Force 2", lng_Def_Ship_Atk_Strat, lng_Def_Ship_Def_Strat, lng_TF_Def_Ship_Atk_Form, lng_TF_Def_Ship_Def_Form)
      call Sys_Create_Empire_Fleet_Task_Force(sys_long_Player_ID, fleet_id, "Task Force 3", Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Kamikaze"), Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Kamikaze"), lng_TF_Def_Ship_Atk_Form, lng_TF_Def_Ship_Def_Form)
      call Sys_Create_Empire_Fleet_Task_Force(sys_long_Player_ID, fleet_id, "Task Force 4", Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt"), Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt"), lng_TF_Def_Ship_Atk_Form, lng_TF_Def_Ship_Def_Form)
      call Sys_Create_Empire_Fleet_Task_Force(sys_long_Player_ID, fleet_id, "Task Force 5", Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt"), Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt"), lng_TF_Def_Ship_Atk_Form, lng_TF_Def_Ship_Def_Form)

      // Debug output
      call Sys_Debug_Print("Ships", "  - " + fleet_name + " created at " + Sys_Get_Solar_System_Name(sys_loc) + " System")
    endfor
  endif

  // Give specific orders to our fleets
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)
  set fleet_count_alt := Get_Number_Of_Fleets()

  if (fleet_count < fleet_count_alt) then
    // Debug output
    call Sys_Debug_Print("Ships", "  - Fleet Count Disagreement! " + Sys_Convert_Long_To_String(fleet_count) + " < " + Sys_Convert_Long_To_String(fleet_count_alt))
    // Correct fleet count
    set fleet_count := fleet_count_alt
  endif

  if (fleet_count > 0) then
    for fleet_index := 1 to fleet_count do
      set fleet_id := Sys_Get_Empire_Fleet_ID(sys_long_Player_ID, fleet_index)
      // Debug output
      call Sys_Debug_Print("Ships", "  - Fleet ID = " + Sys_Convert_Long_To_String(fleet_id))

      if (fleet_id > 0) then
        set fleet_index_alt := fleet_index_alt + 1
        set fleet_type := lst_AI_Fleet_Type.get(fleet_index_alt)
        // Debug Output
        call Sys_Debug_Print("Ships", "  - Fleet Index Alt = " + Sys_Convert_Long_To_String(fleet_index_alt))
        // If our fleet doesn't have a type, give it one
        if (fleet_type = 0) then
          set fleet_type := Get_Fleet_Type_To_Add()
          call lst_AI_Fleet_Type.set(fleet_index_alt, fleet_type)
        endif
        // Maintain the fleet's task forces
        call Maintain_Fleet_Task_Forces(fleet_id)
        // Maintain the fleet's ships
        if Maintain_Fleet_Ships(fleet_id, fleet_index_alt, fleet_type) then
          // Provide orders
          call Give_Specific_Fleet_Orders(fleet_id, fleet_index_alt, fleet_type)
        endif
      else
        // Debug output
        call Sys_Debug_Print("Ships", "    - Phantom Fleet!")
      endif
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Maintain_Fleet_Task_Forces
//------------------------------------------------------------------------
function Maintain_Fleet_Task_Forces returns boolean
params
  fleet_id:                  long
vars
  lst_tf_id:                 longlist
  tf_count:                  long
  tf_index:                  long
  tf_id:                     long
  lst_ship_id:               longlist
  ship_id:                   long
  ship_count:                long
  ship_index:                long
  ship_role:                 string
  ship_strength:             long
  max_strength:              long
  current_leader:            long
  new_leader:                long
  design_type:               string
  atk_ship_count:            long := 0
  def_ship_count:            long := 0
  skr_ship_count:            long := 0
  brd_ship_count:            long := 0
  bom_ship_count:            long := 0
  kam_ship_count:            long := 0
  trp_ship_count:            long := 0
  spt_ship_count:            long := 0
  non_combat_count:          long
  new_atk_strat:             long
  new_def_strat:             long
  new_atk_form:              long
  new_def_form:              long
  TF_formation_mod:          long := 0
begin

  // Get our fleet's task forces
  call Sys_Get_Empire_Fleet_Taskforce_Ids(sys_long_Player_ID, fleet_id, lst_tf_id)
  set tf_count := lst_tf_id.count()

  // Debug output
  call Sys_Debug_Print("Ships", "  - Fleet #" + Sys_Convert_Long_To_String(fleet_id) + " Ships:")

  // Go through each task force and count how many ships we have
  if (tf_count > 0) then
    for tf_index := 1 to tf_count do
      set tf_id := lst_tf_id.get(tf_index)
      call Sys_Get_Empire_Fleet_Taskforce_Ship_Ids(sys_long_Player_ID, fleet_id, tf_id, lst_ship_id)
      set ship_count := lst_ship_id.count()
      set current_leader := Sys_Get_Empire_Fleet_Task_Force_Leader(sys_long_Player_ID, fleet_id, tf_id)
      // Is this task force leader even in the task force?
      if (lst_ship_id.indexof(current_leader) <= 0) then
        set current_leader := 0
      endif
      // No task force leader if there's no ships in the task force!
      if (ship_count = 0) then
        call Sys_Set_Empire_Fleet_Task_Force_Leader(sys_long_Player_ID, fleet_id, tf_id, 0)
      endif
      // Reset Variables
      set new_leader := 0
      set max_strength := 0
      // Debug output
      call Sys_Debug_Print("Ships", "    - Task Force " + Sys_Convert_Long_To_String(tf_index) + " (Leader = " + Sys_Get_Space_Object_Name(current_leader) + ")")

      // Reset design type counts
      set atk_ship_count := 0
      set def_ship_count := 0
      set skr_ship_count := 0
      set brd_ship_count := 0
      set bom_ship_count := 0
      set kam_ship_count := 0
      set trp_ship_count := 0
      set spt_ship_count := 0

      // Reset task force strategies
      set new_atk_strat := 0
      set new_def_strat := 0
      set new_atk_form := 0
      set new_def_form := 0

      // Adjust our TF formation depending on number of ships (0 = Small form; -1 = Medium form; -2 = Large form)
      if (ship_count >= 15) then
        set TF_formation_mod := -1
      endif
      if (ship_count >= 24) then
        set TF_formation_mod := -2
      endif

      // Count the number of each major ship type
      if (ship_count > 0) then
        for ship_index := 1 to ship_count do
          set ship_id := lst_ship_id.get(ship_index)
          set ship_role := Get_Task_Force_Role(ship_id)
          set ship_strength := Calculate_Space_Object_Strength(ship_id)
          // Convert our ship's specific AI design type to its general AI design type
          set design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
          set design_type := Get_General_AI_Design_Type(design_type)
          // Debug output
          call Sys_Debug_Print("Ships", "      - " + Sys_Get_Space_Object_Name(ship_id) + "; Type = " + design_type + "; Role = " + ship_role + "; Strength = " + Sys_Convert_Long_To_String(ship_strength))

          // Count the types of ships
          case design_type
            "Ship (Attack)":
              set atk_ship_count := atk_ship_count + 1
            "Ship (Defense)":
              set def_ship_count := def_ship_count + 1
            "Ship (Seeker)":
              set skr_ship_count := skr_ship_count + 1
            "Ship (Boarding)":
              set brd_ship_count := brd_ship_count + 1
            "Ship (Bombardment)":
              set bom_ship_count := bom_ship_count + 1
            "Ship (Kamikaze)":
              set kam_ship_count := kam_ship_count + 1
            "Transport (Troop)":
              set trp_ship_count := trp_ship_count + 1
            "Ship (Mine Sweeper)":
              set spt_ship_count := spt_ship_count + 1
            "Transport (Supply)":
              set spt_ship_count := spt_ship_count + 1
            "(Ship) Repair":
              set spt_ship_count := spt_ship_count + 1
          endcase

          // Assign the strongest ship as the task force leader
          if (ship_strength > max_strength) then
            set max_strength := ship_strength
            set new_leader := ship_id
          endif
        endfor
      endif

      // If our current leader is not the strongest ship, choose a new leader
      if (current_leader <> new_leader) then
        call Sys_Set_Empire_Fleet_Task_Force_Leader(sys_long_Player_ID, fleet_id, tf_id, new_leader)
        // Debug output
        call Sys_Debug_Print("Ships", "      - Switched TF leader to " + Sys_Get_Space_Object_Name(new_leader))
      endif

      // Update our fleet's task force strategies based on the majority design type present
      if (atk_ship_count > ship_count * 0.5) then
        set new_atk_strat := lng_Atk_Ship_Atk_Strat
        set new_def_strat := lng_Atk_Ship_Def_Strat
        set new_atk_form := lng_TF_Atk_Ship_Atk_Form + TF_formation_mod
        set new_def_form := lng_TF_Atk_Ship_Def_Form + TF_formation_mod
      endif

      if (def_ship_count > ship_count * 0.5) then
        set new_atk_strat := lng_Def_Ship_Atk_Strat
        set new_def_strat := lng_Def_Ship_Def_Strat
        set new_atk_form := lng_TF_Def_Ship_Atk_Form + TF_formation_mod
        set new_def_form := lng_TF_Def_Ship_Def_Form + TF_formation_mod
      endif

      if (skr_ship_count > ship_count * 0.5) then
        set new_atk_strat := lng_Skr_Ship_Atk_Strat
        set new_def_strat := lng_Skr_Ship_Def_Strat
        set new_atk_form := lng_TF_Skr_Ship_Atk_Form + TF_formation_mod
        set new_def_form := lng_TF_Skr_Ship_Def_Form + TF_formation_mod
      endif

      // Update our fleet's task force strategy for specialty ship types
      if (trp_ship_count > 0) then
        set new_atk_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Capture Enemy Planet")
      endif

      if (brd_ship_count > ship_count * 0.2) then
        set new_atk_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Capture Enemy Ships")
      endif

      if (bom_ship_count > ship_count * 0.2) then
        set new_atk_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Bombard Enemy Planet")
      endif

      if (kam_ship_count > ship_count * 0.5) then
        set new_atk_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Kamikaze")
      endif

      if (spt_ship_count > 0) and (new_atk_strat = 0) then
        set new_atk_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt")
        set new_def_strat := Sys_Get_Strategy_With_Name(sys_long_Player_ID, "Don't Get Hurt")
      endif

      if (new_atk_strat = 0) then
        set new_atk_strat := lng_Atk_Ship_Atk_Strat
      endif
      if (new_def_strat = 0) then
        set new_def_strat := lng_Atk_Ship_Def_Strat
      endif

      if (new_atk_form = 0) then
        set new_atk_form := lng_TF_Atk_Ship_Atk_Form
      endif
      if (new_def_form = 0) then
        set new_def_form := lng_TF_Atk_Ship_Def_Form
      endif

      // Update our task force's strategy and formation
      call Sys_Set_Empire_Fleet_Taskforce_Attack_Strategy(sys_long_Player_ID, fleet_id, tf_id, new_atk_strat)
      call Sys_Set_Empire_Fleet_Taskforce_Defense_Strategy(sys_long_Player_ID, fleet_id, tf_id, new_def_strat)
      call Sys_Set_Empire_Fleet_Taskforce_Attack_Formation(Sys_long_Player_ID, fleet_id, tf_id, new_atk_form)
      call Sys_Set_Empire_Fleet_Taskforce_Defense_Formation(Sys_long_Player_ID, fleet_id, tf_id, new_def_form)
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Maintain_Fleet_Ships
//------------------------------------------------------------------------
function Maintain_Fleet_Ships returns boolean
params
  fleet_id:                  long
  fleet_index:               long
  fleet_type:                long
vars
  orders_given:              boolean := FALSE
  ship_count:                long
  atk_ship_count:            long
  fleet_count:               long
  fleet_name:                string
  fleet_strength:            long
  fleet_xp:                  real
  fleet_leader:              long
  fleet_sys_loc:             long
  fleet_sect_loc:            long
  fleet_movement:            long := 999
  fleet_mine_sweep_count:    long
  fleet_cur_supply:          long
  fleet_max_supply:          long
  fleet_supply_per_move:     long
  fleet_pct_supply:          long
  fleet_range:               long
  fleet_max_range:           long
  fleet_status:              long
  check_orders:              boolean := TRUE
  current_orders:            long
  order_target_sys_loc:      long
  order_target_sect_loc:     long
  order_target_dist:         long
  order_target_id:           long
  target_sys_loc:            long
  target_sect_loc:           long
  target_dist:               long
  target_id:                 long
  lst_fleet_ships:           longlist
  ship_id:                   long
  ship_name:                 string
  ship_movement:             long
  ship_strength:             long
  max_strength:              long := 0
  new_fleet_leader:          long := 0
  ship_mine_sweep_count:     long
  design_type:               string
  ships_joining_this_fleet:  long
  ships_wanted_this_fleet:   long
  index:                     long
  ship_removed:              boolean
  ship_max_dmg_to_drop:      long := 30
  unit_needed:               string
  skip_checks:               boolean := FALSE
  cargo_needed:              boolean := FALSE
  fleet_at_spaceyard:        boolean := FALSE
  fleet_active:              boolean := TRUE
  fleet_repair:              boolean := FALSE
  fleet_replenish:           boolean := FALSE
  fleet_retrofit:            boolean := FALSE
  fleet_resupply:            boolean := FALSE
  fleet_can_capture:         boolean := FALSE
begin

  // Get our fleet's details
  set fleet_name := "Fleet #" + Sys_Convert_Long_To_String(fleet_id)
  set fleet_leader := Sys_Get_Empire_Fleet_Leader(sys_long_Player_ID, fleet_id)
  set fleet_xp := Sys_Get_Empire_Fleet_Experience(sys_long_Player_ID, fleet_id)
  set fleet_sys_loc := Sys_Get_Empire_Fleet_System_Location(sys_long_Player_ID, fleet_id)
  set fleet_sect_loc := Sys_Get_Empire_Fleet_Sector_Location(sys_long_Player_ID, fleet_id)
  set fleet_count := Sys_Get_Empire_Fleet_Count(sys_long_Player_ID)
  set fleet_at_spaceyard := Sys_Is_Space_Yard_At_Location(sys_long_player_ID, fleet_sys_loc, fleet_sect_loc)
  set ships_joining_this_fleet := Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_JOIN_FLEET, 0, 0, fleet_id)

  // Debug output
  call Sys_Debug_Print("Ships", "  - " + fleet_name + " Status:")
  call Sys_Debug_Print("Ships", "    - Current location = " + Sys_Get_Solar_System_Name(fleet_sys_loc) + " System " + Convert_Sector_To_String(fleet_sect_loc) + " SY = " + Sys_Convert_Boolean_To_String(fleet_at_spaceyard))

  // Determine how many ships we want for our fleet
  if (fleet_type = FLEET_TYPE_ATTACK) or (fleet_type = 0) then
    if (fleet_count > 0) and (lng_Pct_Fleets_For_Attack > 0) then
      set ships_wanted_this_fleet := Sys_Trunc((lng_AI_Available_Fleet_Ships_Count * lng_Pct_Ships_For_Attack_Fleets) / (fleet_count * lng_Pct_Fleets_For_Attack))
    endif
    // Debug output
    call Sys_Debug_Print("Ships", "    - Attack Fleet")
  else
    if (fleet_count > 0) and (lng_Pct_Fleets_For_Defense > 0) then
      set ships_wanted_this_fleet := Sys_Trunc((lng_AI_Available_Fleet_Ships_Count * lng_Pct_Ships_For_Defense_Fleets) / (fleet_count * lng_Pct_Fleets_For_Defense))
    endif
    // Debug output
    call Sys_Debug_Print("Ships", "    - Defense Fleet")
  endif

  // Debug output
  call Sys_Debug_Print("Ships", "    - Leader = " + Sys_Get_Space_Object_Name(fleet_leader))

  // Get a list of the ships in our fleet
  call Sys_Get_Empire_Fleet_Ship_List(sys_long_Player_ID, fleet_id, lst_fleet_ships)
  set ship_count := lst_fleet_ships.count()

  if (ship_count > 0) then
    // Check to see if our fleet already has orders
    set orders_given := (Sys_Get_Empire_Fleet_Order_Count(sys_long_Player_ID, fleet_id) > 0)

    // Does our fleet have lots of obsolete ships?
    if (fleet_at_spaceyard) then
      // Encourage a fleet retrofit if we are at a Space Yard if more than 60% of our ships are 30 turns obsolete
      if Do_Ships_In_Fleet_Need_Retrofit(fleet_id, 30, 60) then
        set fleet_retrofit := TRUE
      endif
    else
      // Encourage a fleet retrofit regardless of location if more than 90% of our ships are 30 turns obsolete
      if (sys_Get_Random_Long(1, 3 + lng_AI_Categorization) = 1) then
        if Do_Ships_In_Fleet_Need_Retrofit(fleet_id, 30, 90) then
          set fleet_retrofit := TRUE
        endif
      endif
    endif

    // Look through our fleet's ships to see if any need to be repaired, retrofitted or re-supplied
    loop
      set index := index + 1
      set ship_id := lst_fleet_ships.get(index)
      set ship_name := Sys_Get_Space_Object_Name(ship_id)
      set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
      set ship_strength := Calculate_Space_Object_Strength(ship_id)
      set ship_mine_sweep_count := Get_Mine_Sweep_Count(ship_id) + Sys_Divide_Long(Sys_Get_Space_Object_Current_Armor_Structure(ship_id), 500)
      set ship_removed := FALSE
      set cargo_needed := FALSE
      set skip_checks := FALSE
      set design_type := Get_General_AI_Design_Type(Sys_Get_Space_Object_AI_Design_Type(ship_id))

      // Debug output - Note our fleet's current order
      if (check_orders) then
        set current_orders := Sys_Get_Space_Object_Order_Type(ship_id, 1)
        // What orders does our fleet have?
        if (current_orders > 0) then
          set order_target_sys_loc := Sys_Get_Space_Object_Order_System_Location(ship_id, 1)
          set order_target_sect_loc := Sys_Get_Space_Object_Order_Sector_Location(ship_id, 1)
          set order_target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, order_target_sys_loc, order_target_sect_loc)
          set order_target_id := Sys_Get_Space_Object_Order_Target_Space_Object_ID(ship_id, 1)
          // Debug output
          call Sys_Debug_Print("Ships", "    - Executing order " + Get_Order_Name(current_orders))
          call Sys_Debug_Print("Ships", "      - Destination = " + Sys_Get_Solar_System_Name(order_target_sys_loc) + " System " + Convert_Sector_To_String(order_target_sect_loc))
          call Sys_Debug_Print("Ships", "      - Distance = " + Sys_Convert_Long_To_String(order_target_dist))
          // Note target name
          if (order_target_id > 0) then
            // Debug output
            call Sys_Debug_Print("Ships", "      - Target = " + Sys_Get_Space_Object_Name(order_target_id))
          endif
          // Don't bother checking other ships in our fleet for orders
          set check_orders := FALSE
        endif
        // Clear orders if we are no longer close to our target due to pathfinding issues
        if (order_target_dist > 30) then
          call Sys_Empire_Fleet_Clear_Orders(sys_long_player_ID, fleet_id)
          set orders_given := FALSE
          // Debug output
          call Sys_Debug_Print("Ships", "      - Cleared orders since target is too far away (shortest path not available)")
        endif
      endif

      // Remove our Carriers/Transports from the fleet if their current capacity is low
      case (design_type)
        "Carrier (Fighter)":
          set cargo_needed := Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter", 50)
          set unit_needed := "Fighter"
        "Carrier (Drone)":
          set cargo_needed := Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Drone", 50)
          set unit_needed := "Drone"
        "Transport (Troop)":
          set cargo_needed := Do_We_Need_More_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, "Troop", 50)
          set unit_needed := "Troop"
          // Note if our fleet can capture
          if (not fleet_can_capture) then
            if (not cargo_needed) then
              set fleet_can_capture := TRUE
            endif
          endif
        "Ship (Repair)":
          set ship_max_dmg_to_drop := ship_max_dmg_to_drop + 10
      endcase

      // Release our ship to pick up more cargo if needed
      if (cargo_needed) then
        set ship_removed := Sys_Give_Space_Object_Order_Leave_Fleet(ship_id, fleet_id)
        // Order our ship to pick up more cargo
        call Sys_Space_Object_Clear_Orders(ship_id)
        call Ship_Order_Load_Cargo(ship_id, CARGO_ITEM_TYPE_UNIT, unit_needed, FALSE)
        set skip_checks := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "      - " + ship_name + " released to pick up " + unit_needed + "s")
      endif

      // Drop ships from our fleet that are critically damaged if we are not at a Space Yard
      if (not fleet_at_spaceyard) then
        if Does_Ship_Need_Repair(ship_id, ship_max_dmg_to_drop, TRUE, FALSE, FALSE) then
          set ship_removed := Sys_Give_Space_Object_Order_Leave_Fleet(ship_id, fleet_id)
          // Order our ship to the nearest repair location
          call Sys_Space_Object_Clear_Orders(ship_id)
          call Send_Ship_To_Repair(ship_id)
          set skip_checks := TRUE
        endif
      endif

      // Orders if we are at a Space Yard
      if (fleet_at_spaceyard) and (fleet_retrofit) then
        // Does our ship need retrofit?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Retrofit") and (not skip_checks) then
          if Does_Ship_Need_Retrofitting(ship_id, TRUE) then
            // Debug output
            call Sys_Debug_Print("Ships", "    - " + ship_name + " (" + design_type + ") released for retrofit")
            // Remove our ship from the fleet
            set ship_removed := Sys_Give_Space_Object_Order_Leave_Fleet(ship_id, fleet_id)
            // Order our ship to be retrofit
            call Sys_Space_Object_Clear_Orders(ship_id)
            call Order_Retrofit(ship_id)
            set skip_checks := TRUE
          endif
        endif
        // Does our ship need to be scrapped?
        if Sys_Using_AI_Minister(sys_long_Player_ID, "Ships - (All) Scrapping") and (not skip_checks) then
          if Does_Ship_Need_Scrapping(ship_id) then
            // Debug output
            call Sys_Debug_Print("Ships", "    - " + ship_name + " (" + design_type + ") released for scrapping")
            // Remove our ship from the fleet
            set ship_removed := Sys_Give_Space_Object_Order_Leave_Fleet(ship_id, fleet_id)
            // Order our ship to be scrapped
            call Sys_Space_Object_Clear_Orders(ship_id)
            call Order_Scrap(ship_id)
            set skip_checks := TRUE
          endif
        endif
      endif

      // Note fleet attributes
      if (ship_removed) then
        call lst_fleet_ships.delete(index)
        set index := index - 1
        set ship_count := ship_count - 1
      else
        // Track our fleet's strength
        set fleet_strength := fleet_strength + ship_strength
        // Identify our strongest ship
        if (ship_strength > max_strength) then
          set max_strength := ship_strength
          set new_fleet_leader := ship_id
        endif
        // Track our fleet's current supplies
        set fleet_cur_supply := fleet_cur_supply + Sys_Get_Space_Object_Current_Supply(ship_id)
        set fleet_supply_per_move := fleet_supply_per_move + Sys_Get_Space_Object_Supplies_Used_Per_Move(ship_id)
        // Track our fleet's maximum supplies
        if (design_type = "Transport (Supply)") then
          set fleet_max_supply := fleet_max_supply + Sys_Divide_Long(Sys_Get_Space_Object_Maximum_Supply(ship_id), 4)
        else
          set fleet_max_supply := fleet_max_supply + Sys_Get_Space_Object_Maximum_Supply(ship_id)
        endif
        // Track our fleet's maximum movement
        if (ship_movement < fleet_movement) then
          set fleet_movement := ship_movement
        endif
        // Track our fleet's mine sweep capacity
        set fleet_mine_sweep_count := fleet_mine_sweep_count + ship_mine_sweep_count
      endif

      // Count the number of combat ships we have in our fleet
      if (design_type = "Ship (Attack)") or (design_type = "Ship (Defense)") or (design_type = "Ship (Seeker)") or  (design_type = "Ship (Attack Base)") or (design_type = "Ship (Boarding)") or (design_type = "Ship (Bombardment)") or (design_type = "Ship (Kamikaze)") or (design_type = "Ship (Point-Defense)") then
        set atk_ship_count := atk_ship_count + 1
      endif

      exitwhen (index >= ship_count) or (ship_count = 0)
    endloop

    // Determine our fleet's range
    if (fleet_max_supply > 0) and (fleet_supply_per_move > 0) then
      set fleet_pct_supply := Sys_Divide_Long(fleet_cur_supply * 100, fleet_max_supply)
      set fleet_max_range := Sys_Divide_Long(fleet_max_supply, fleet_supply_per_move)
      set fleet_range := Sys_Divide_Long(fleet_cur_supply, fleet_supply_per_move)
    endif

    // Update our fleet leader if a new one is identified
    if (new_fleet_leader > 0) then
      set fleet_leader := new_fleet_leader
      call Sys_Set_Empire_Fleet_Leader(sys_long_player_ID, fleet_id, fleet_leader)
      call lst_AI_Fleet_Leader.set(fleet_index, fleet_leader)
    endif

    // Debug output
    call Sys_Debug_Print("Ships", "    - Combat/Total Ships = " + Sys_Convert_Long_To_String(atk_ship_count) + "/" + Sys_Convert_Long_To_String(ship_count))
    call Sys_Debug_Print("Ships", "    - Wanted/Joining Ships = " + Sys_Convert_Long_To_String(ships_wanted_this_fleet) + "/" Sys_Convert_Long_To_String(ships_joining_this_fleet))
    call Sys_Debug_Print("Ships", "    - Maximum movement = " + Sys_Convert_Long_To_String(fleet_movement))
    call Sys_Debug_Print("Ships", "    - Leader = " + Sys_Get_Space_Object_Name(fleet_leader))
    call Sys_Debug_Print("Ships", "    - Experience = " + Sys_Convert_Real_To_String(fleet_xp))
    call Sys_Debug_Print("Ships", "    - Strength = " + Sys_Convert_Long_To_String(fleet_strength))
    call Sys_Debug_Print("Ships", "    - Mine sweep count = " + Sys_Convert_Long_To_String(fleet_mine_sweep_count))
    call Sys_Debug_Print("Ships", "    - Supply capacity estimate = " + Sys_Convert_Long_To_String(fleet_pct_supply) + "%")
    call Sys_Debug_Print("Ships", "    - Maximum range estimate = " + Sys_Convert_Long_To_String(fleet_max_range) + " sectors")
    call Sys_Debug_Print("Ships", "    - Current range estimate = " + Sys_Convert_Long_To_String(fleet_range) + " sectors")

    // Do the ships in our fleet still need repair?
    if Do_Ships_In_Fleet_Need_Repair(fleet_id) then
      set fleet_repair := TRUE
      // Debug output
      call Sys_Debug_Print("Ships", "    - Repairs required")
    endif

    // Does our fleet need more ships or can it be active?
    if (not orders_given) then
      if (ship_count < ships_wanted_this_fleet * 0.5) or (atk_ship_count < ship_count * 0.5) then
        set fleet_active := FALSE
        set fleet_replenish := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "    - Replenish ships")
      else
        set fleet_active := TRUE
        call Sys_Set_Empire_Fleet_Waiting_For_Ships(sys_long_Player_ID, fleet_id, FALSE)
        // Increase mine fleet sweeping ability from brute force
        set fleet_mine_sweep_count := fleet_mine_sweep_count + (ship_count * 2)
        // Debug output
        call Sys_Debug_Print("Ships", "    - Active")
      endif
    endif

    // Does our fleet need to retrofit or repair?
    if (fleet_retrofit) or (fleet_repair) then
      // Update our fleet's status if already at Space Yard
      if (fleet_at_spaceyard) then
        set orders_given := TRUE
        set fleet_status := FLEET_STATUS_RETROFIT
        call Sys_Set_Empire_Fleet_Waiting_For_Ships(sys_long_Player_ID, fleet_id, TRUE)
        // Debug output
        call Sys_Debug_Print("Ships","    - Retrofitting/Repairing/Replenishing at Space Yard ")
      else
        // Find nearest Space Yard Hub to send our fleet to retrofit/repair
        set target_id := Find_Nearest_Object_In_List(lst_AI_Our_Space_Yard_Hubs, fleet_sys_loc, fleet_sect_loc, FALSE, FALSE)
        // Order our fleet to retrofit
        if (target_id > 0) then
          set target_sys_loc := Sys_Get_Space_Object_System_Location(target_id)
          set target_sect_loc := Sys_Get_Space_Object_Sector_Location(target_id)
          set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
          set fleet_status := FLEET_STATUS_RETROFIT
          // Debug output
          call Sys_Debug_Print("Ships","    - Move to Space Yard Hub in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc) + " for retrofit/repair/replenish")
        else
          if Find_Nearest_Space_Yard(fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc) then
            call Sys_Empire_Fleet_Clear_Orders(sys_long_Player_ID, fleet_id)
            set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
            set fleet_status := FLEET_STATUS_RETROFIT
            // Debug output
            call Sys_Debug_Print("Ships","    - Move to Space Yard in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc) + " for retrofit/repair/replenish")
          endif
        endif
      endif
    endif

    // Does our fleet need to be resupplied?
    if (fleet_pct_supply < 50) then
      set fleet_resupply := TRUE
    else
      set fleet_resupply := FALSE
    endif
    // Don't resupply if our destination is in a system with a Resupply Depot
    if (fleet_range > order_target_dist) and (lst_AI_Our_Resupply_Systems.indexof(order_target_sys_loc) > 0) then
      set fleet_resupply := FALSE
    endif
    // Order our ship to resupply and update fleet's status
    if (fleet_resupply) then
      call Sys_Empire_Fleet_Clear_Orders(sys_long_Player_ID, fleet_id)
      set orders_given := Sys_Give_Empire_Fleet_Order_Resupply_At_Nearest(sys_long_Player_ID, fleet_id)
      set fleet_status := FLEET_STATUS_RESUPPLY
      // Debug output
      call Sys_Debug_Print("Ships","    - Resupply")
    endif

    // Send inactive fleets to the nearest Space Yard or Resupply Depot
    if (not fleet_active) and (not orders_given) then
      if (fleet_at_spaceyard) then
        // Update our fleet's flag if waiting for ships
        call Sys_Set_Empire_Fleet_Waiting_For_Ships(sys_long_Player_ID, fleet_id, TRUE)
        set fleet_status := FLEET_STATUS_WAITING_FOR_SHIPS
        // Debug output
        call Sys_Debug_Print("Ships", "    - Inactive at Space Yard")
        call Sys_Debug_Print("Ships", "    - Waiting for ships")
      else
        // Find the nearest Space Yard Hub
        set target_id := Find_Nearest_Object_In_List(lst_AI_Our_Space_Yard_Hubs, fleet_sys_loc, fleet_sect_loc, FALSE, FALSE)
        // Order our fleet to the Space Yard Hub to replenish ships
        if (target_id > 0) then
          set target_sys_loc := Sys_Get_Space_Object_System_Location(target_id)
          set target_sect_loc := Sys_Get_Space_Object_Sector_Location(target_id)
          set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
          set fleet_status := FLEET_STATUS_REPLENISH_SHIPS
          // Debug output
          call Sys_Debug_Print("Ships","    - Move to Space Yard Hub in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc) + " to replenish ships")
        endif
      endif
    endif
  else
    // Fleets with no ships
    if (fleet_at_spaceyard) then
      set orders_given := Sys_Set_Empire_Fleet_Waiting_For_Ships(sys_long_Player_ID, fleet_id, TRUE)
      set fleet_active := FALSE
      set fleet_status := FLEET_STATUS_WAITING_FOR_SHIPS
      // Debug output
      call Sys_Debug_Print("Ships", "    - No ships! Waiting for ships")
      call Sys_Debug_Print("Ships", "    - Wanted/Joining Ships = " + Sys_Convert_Long_To_String(ships_wanted_this_fleet) + "/" Sys_Convert_Long_To_String(ships_joining_this_fleet))
    else
      // Disband fleet
      call Sys_Disband_Empire_Fleet(sys_long_Player_ID, fleet_id)
      set fleet_active := FALSE
      // Debug output
      call Sys_Debug_Print("Ships", "    - No Ships! Disband fleet")
    endif
  endif

  if (orders_given) then
    set fleet_active := FALSE
  endif

  // Update our fleet list variables
  call lst_AI_Fleet_Type.set(fleet_index, fleet_type)
  call lst_AI_Fleet_Status.set(fleet_index, fleet_status)
  call lst_AI_Fleet_Sys_Loc.set(fleet_index, fleet_sys_loc)
  call lst_AI_Fleet_Sect_Loc.set(fleet_index, fleet_sect_loc)
  call lst_AI_Fleet_Strength.set(fleet_index, fleet_strength)
  call lst_AI_Fleet_Movement.set(fleet_index, fleet_movement)
  call lst_AI_Fleet_Range.set(fleet_index, fleet_range)
  call lst_AI_Fleet_Mine_Sweep_Count.set(fleet_index, fleet_mine_sweep_count)

  if (fleet_can_capture) then
    call str_AI_Fleet_Capture.add("TRUE")
  else
    call str_AI_Fleet_Capture.add("FALSE")
  endif

  return fleet_active
end

//------------------------------------------------------------------------
// Give_Specific_Fleet_Orders
//------------------------------------------------------------------------
function Give_Specific_Fleet_Orders returns boolean
params
  fleet_id:                  long
  fleet_index:               long
  fleet_type:                long
vars
  orders_given:              boolean := FALSE
  order_to_border_sys:       boolean := FALSE
  hold_at_border_warp_pt:    boolean := FALSE
  loop_count:                long
  list_count:                long
  list_index:                long
  fleet_strength:            long
  fleet_sys_loc:             long
  fleet_sect_loc:            long
  fleet_movement:            long
  fleet_range:               long
  fleet_atk_dist:            long
  fleet_mine_sweep_count:    long
  target_count:              long
  target_index:              long
  target_obj_id:             long
  target_sys_loc:            long
  target_sect_loc:           long
  target_wp_id:              long
  target_dist:               long
  target_name:               string
  target_priority:           long
  found_index:               long
  found_obj_id:              long
  found_sys_loc:             long
  found_sect_loc:            long
  found_wp_id:               long
  wp_dest_sys_loc:           long
  wp_dest_sect_loc:          long
  enemy_owner:               long
  enemy_fear:                long
  enemy_strength:            long
  enemy_mine_count:          long
  min_dist:                  long := 50
  max_chance:                long
  fleet_can_capture:         boolean := FALSE
  fleet_retreat:             boolean := FALSE
  same_sys_only:             boolean := FALSE
  single_target_only:        boolean := FALSE
begin

  // Get our fleet's details
  set fleet_sys_loc := lst_AI_Fleet_Sys_Loc.get(fleet_index)
  set fleet_sect_loc := lst_AI_Fleet_Sect_Loc.get(fleet_index)
  set fleet_strength := lst_AI_Fleet_Strength.get(fleet_index)
  set fleet_movement := lst_AI_Fleet_Movement.get(fleet_index)
  set fleet_range := lst_AI_Fleet_Range.get(fleet_index)
  set fleet_mine_sweep_count := lst_AI_Fleet_Mine_Sweep_Count.get(fleet_index)

  // Adjust the attack range if we're on the AI team
  if bool_AI_Team_Mode_On then
    set fleet_atk_dist := Sys_Min_Long(30, Sys_Divide_Long(fleet_range, 5))
  else
    set fleet_atk_dist := Sys_Min_Long(30, Sys_Divide_Long(fleet_range, 2))
  endif

  if (str_AI_Fleet_Capture.get(fleet_index) = "TRUE") then
    set fleet_can_capture := TRUE
  endif

  // Clear previous target lists
  call gbl_lst_target_loc_type.clear()
  call gbl_lst_target_index.clear()
  call gbl_lst_target_obj_id.clear()
  call gbl_lst_target_sys_loc.clear()
  call gbl_lst_target_sect_loc.clear()

  // Fleet Priority #1 - Targeted Locations (Suspected)
  // Can cancel existing orders
  set list_count := lst_AI_Target_To_Defend.count()
  // Go through the list
  if (list_count > 0) then
    set list_index := 0
    // Look through our list of targeted locations and see if we can actively defend one with our fleet
    loop
      set list_index := list_index + 1
      // How far is the targeted location for our fleet?
      set target_obj_id := lst_AI_Target_To_Defend.get(list_index)
      set target_name := Sys_Get_Space_Object_Name(target_obj_id)
      set target_dist := lst_AI_Target_To_Defend_Dist.get(list_index)
      set target_sys_loc := Sys_Get_Space_Object_System_Location(target_obj_id)
      set target_sect_loc := Sys_Get_Space_Object_Sector_Location(target_obj_id)
      set fleet_atk_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
      // If our fleet is close or closer than the attacks then move to the location
      if (fleet_atk_dist <= fleet_movement) or (fleet_atk_dist <= target_dist) then
        if (orders_given) then
          call Sys_Empire_Fleet_Clear_Orders(sys_long_player_ID, fleet_id)
          // Debug output
          call Sys_Debug_Print("Ships","    - Canceled orders to actively defend target!")
        endif
        // Order the fleet to the location
        set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        // Debug output
        call Sys_Debug_Print("Ships","    - Defend active target " + target_name + " in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
        // Remove the location
        call lst_AI_Target_To_Defend.delete(list_index)
        call lst_AI_Target_To_Defend_Dist.delete(list_index)
        call lst_AI_Target_To_Defend_Count.delete(list_index)
      endif
      exitwhen (list_index >= list_count) or (orders_given)
    endloop
  endif

  // Fleet Priority #2 - Defense Locations (Enemy targets in our colony systems)
  if (not orders_given) then
    set list_count := lst_AI_Defense_Location_System.count()
    // Go through our list of defense locations and find targets
    if (list_count > 0) then
      // Get a list of targets for our fleet to attack
      set target_count := Get_Target_To_Attack(LOCATION_TYPE_DEFENSE, 3, fleet_sys_loc, fleet_sect_loc, fleet_movement, fleet_strength, SPACE_OBJECT_TYPE_SHIP, fleet_mine_sweep_count, fleet_atk_dist, FALSE, TRUE, TRUE, same_sys_only, single_target_only)
      // Set our fleet to retreat if needed
      if (target_count = -1) then
        set fleet_retreat := TRUE
      endif
    endif

    // Order our fleet to attack the selected targets
    set list_count := gbl_lst_target_index.count()

    if (list_count > 0) and (not fleet_retreat) then
      for list_index := 1 to list_count do
        set target_index := gbl_lst_target_index.get(list_index)
        set target_obj_id := gbl_lst_target_obj_id.get(list_index)
        set target_sys_loc := gbl_lst_target_sys_loc.get(list_index)
        set target_sect_loc := gbl_lst_target_sect_loc.get(list_index)
        set target_name := Sys_Get_Space_Object_Name(target_obj_id)
        // Debug output
        call Sys_Debug_Print("Ships","    - Defend against " + target_name + " in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
        // Order our fleet to attack
        if (Sys_Get_Space_Object_Type(target_obj_id) = SPACE_OBJECT_TYPE_PLANET) then
          set orders_given := Sys_Give_Empire_Fleet_Order_Attack_Move(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        else
          set orders_given := Sys_Give_Empire_Fleet_Order_Attack_Seek(sys_long_Player_ID, fleet_id, target_obj_id)
        endif
        // Remove the location
        call remove_location(LOCATION_TYPE_DEFENSE, lst_AI_Defense_Location_Ship_ID.indexof(target_obj_id))
      endfor
    endif
  endif

  // If our fleet is retreating, send it to the system's capital
  if (fleet_retreat) then
    set target_sys_loc := gbl_lst_target_sys_loc.get(1)
    set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
    // Order our fleet to move to system capital
    if (target_sect_loc > 0) then
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships","    - Retreat to " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
    endif
  endif

  // Fleet Priority #3 - Nearby Enemies (Enemy ships in our non-colony systems)
  if (not orders_given) then
    set list_count := lst_AI_Nearby_Enemy_Location_System.count()
    // Go through our list of nearby enemy locations and find targets
    if (list_count > 0) then
      // Get a list of targets for our fleet to attack
      set target_count := Get_Target_To_Attack(LOCATION_TYPE_NEARBY_ENEMY, 3, fleet_sys_loc, fleet_sect_loc, fleet_movement, fleet_strength, SPACE_OBJECT_TYPE_SHIP, fleet_mine_sweep_count, fleet_atk_dist, FALSE, FALSE, TRUE, same_sys_only, single_target_only)
    endif

    // Order our fleet to attack the selected targets
    set list_count := gbl_lst_target_index.count()

    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_index := gbl_lst_target_index.get(list_index)
        set target_obj_id := gbl_lst_target_obj_id.get(list_index)
        set target_sys_loc := gbl_lst_target_sys_loc.get(list_index)
        set target_sect_loc := gbl_lst_target_sect_loc.get(list_index)
        set target_name := Sys_Get_Space_Object_Name(target_obj_id)
        // Debug output
        call Sys_Debug_Print("Ships","    - Attack " + target_name + " in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
        // Order our fleet to attack
        set orders_given := Sys_Give_Empire_Fleet_Order_Attack_Seek(sys_long_Player_ID, fleet_id, target_obj_id)
        // Remove the location to avoid giving our fleets duplicate orders
        call remove_location(LOCATION_TYPE_NEARBY_ENEMY, lst_AI_Nearby_Enemy_Location_Ship_ID.indexof(target_obj_id))
      endfor
    endif
  endif

  // Fleet Priority #3a - Follow up Demands (Move to a colony in a disputed system where a demand was made)
  if (not orders_given) then
    set list_count := lst_AI_Request_Location_System.count()
    // Find the nearest system where a demand request has been made
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := lst_AI_Request_Location_System.get(list_index)
        set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Is this request location closer than the previous ones?
        if (target_dist < min_dist) then
          set min_dist := target_dist
          set found_sys_loc := target_sys_loc
          set found_sect_loc := target_sect_loc
          set found_index := list_index
        endif
      endfor
      // Order our fleet to a colony in the demand request system
      if (target_sys_loc > 0) then
        set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, found_sys_loc, found_sect_loc)
        // Remove the request system to visit to avoid duplicate orders
        call lst_AI_Request_Location_System.delete(found_index)
        // Debug output
        call Sys_Debug_Print("Ships","    - Ordered to support request in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
      endif
    endif
  endif

  // Fleet Priority #3b - Follow up Request to Remove Ships From System
  if (not orders_given) then
    if (lst_AI_Remove_Ships_From_System.indexof(fleet_sys_loc) > 0) then
      // Randomize our option
      if (Sys_Get_Random_Long(1, 2) = 1) then
        set order_to_border_sys := TRUE
        set orders_given := TRUE
      else
        set hold_at_border_warp_pt := TRUE
        set orders_given := TRUE
      endif
    endif
  endif

  // Fleet Priority #4 - Prepare to Defend (Defense fleets to hold in defense systems)
  if (not orders_given) and (fleet_type = FLEET_TYPE_DEFENSE) and (Sys_Get_Random_Long(1, 20 - lng_Politics_State_Modifier) > 10) then
    set list_count := gbl_lst_ai_state_defend_systems.count()
    // Find the nearest colony in a defense system to our fleet
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := gbl_lst_ai_state_defend_systems.get(list_index)
        set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Is the system insufficiently protected?
        if (lst_AI_Our_Protected_Systems.get(target_sys_loc) = 0) then
          // Is this colony closer than the previous ones and still unprotected?
          if (Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_MOVETO, target_sys_loc, target_sect_loc, 0) < 1) then
            if (target_dist < min_dist) and (gbl_lst_sys_protected.indexof(target_sys_loc) <= 0) then
              set found_sys_loc := target_sys_loc
              set found_sect_loc := target_sect_loc
              set min_dist := target_dist
            endif
          endif
        endif
      endfor
    endif
    // Order our fleet to the colony
    if (found_sys_loc > 0) then
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, found_sys_loc, found_sect_loc)
      // Add to list of protected systems to avoid duplicate orders
      call gbl_lst_sys_protected.add(found_sys_loc)
      // Debug output
      call Sys_Debug_Print("Ships","    - Ordered to protect " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
    endif
  endif

  // Fleet Priority #5 - Attack Locations (Attack enemy colonies in our non-colony systems)
  if (not orders_given) and (fleet_type = FLEET_TYPE_ATTACK) then
    set list_count := lst_AI_Attack_Location_System.count()
    // Go through our list of attack locations and find targets
    if (list_count > 0) then
      // Get a list of targets for our fleet to attack
      set target_count := Get_Target_To_Attack(LOCATION_TYPE_ATTACK, 3, fleet_sys_loc, fleet_sect_loc, fleet_movement, fleet_strength, SPACE_OBJECT_TYPE_SHIP, fleet_mine_sweep_count, fleet_atk_dist, TRUE, FALSE, TRUE, same_sys_only, single_target_only)
    endif

    // Order our fleet to attack the selected targets
    set list_count := gbl_lst_target_index.count()

    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_index := gbl_lst_target_index.get(list_index)
        set target_obj_id := gbl_lst_target_obj_id.get(list_index)
        set target_sys_loc := gbl_lst_target_sys_loc.get(list_index)
        set target_sect_loc := gbl_lst_target_sect_loc.get(list_index)
        set target_name := Sys_Get_Space_Object_Name(target_obj_id)
        // Debug output
        call Sys_Debug_Print("Ships","    - Attack " + target_name + " in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
        // Order our fleet to attack
        set orders_given := Sys_Give_Empire_Fleet_Order_Attack_Move(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        // Remove the attack location to avoid giving our fleets duplicate orders
        call remove_location(LOCATION_TYPE_ATTACK, lst_AI_Attack_Location_Ship_ID.indexof(target_obj_id))
      endfor
    endif
  endif

  // Fleet Priority #6 - Is there an empty minefield we need to clear (due to marked minefield issue where toggle doesn't clear after first sweep)
  set list_count := lst_AI_Marked_Minefield_Sys.count()
  // Check for zero mine minefields that we can use "attack move" to clear
  if (list_count > 0) then
    set list_index := lst_AI_Marked_Minefield_Sys.indexof(fleet_sys_loc)
    // If we are in the same system as the empty minefield then we should "clear" it
    if (list_index > 0) then
      set target_sys_loc := lst_AI_Marked_Minefield_Sys.get(list_index)
      set target_sect_loc := lst_AI_Marked_Minefield_Sect.get(list_index)
      set target_count := lst_AI_Marked_Minefield_Count.get(list_index)
      // Make sure it has no mines!
      if (target_count = 0) then
        // Note should add protection to avoid attacking strong force
        // Use "Attack Move" order to force the fleet into the marked minefield
        set orders_given := Sys_Give_Empire_Fleet_Order_Attack_Move(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        // Remove the location
        call lst_AI_Marked_Minefield_Sys.delete(list_index)
        call lst_AI_Marked_Minefield_Sect.delete(list_index)
        call lst_AI_Marked_Minefield_Count.delete(list_index)
        // Debug output
        call Sys_Debug_Print("Ships", "  - Ordered to clear marked minefield in " + Sys_Get_Solar_System_Name(target_sys_loc) + " System " + Convert_Sector_To_String(target_sect_loc))
      endif
    endif
  endif

  // Fleet Priority #7 - Prepare to Attack (Send fleet to staging system)
  if (not orders_given) and (fleet_type = FLEET_TYPE_ATTACK) then
    set list_count := gbl_lst_ai_state_buildup_systems.count()
    // Pending
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := gbl_lst_ai_state_buildup_systems.get(list_index)
        set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Pending
        if (Sys_Get_Number_Of_Ships_With_Order(sys_long_Player_ID, ORDER_MOVETO, target_sys_loc, target_sect_loc, 0) < 1) then
          if (target_dist < min_dist) and (gbl_lst_sys_protected.indexof(target_sys_loc) <= 0) then
            set found_sys_loc := target_sys_loc
            set found_sect_loc := target_sect_loc
            set min_dist := target_dist
          endif
        endif
      endfor
    endif
    // Order our fleet to the staging system
    if (found_sys_loc > 0) then
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, found_sys_loc, found_sect_loc)
      // Pending
      call gbl_lst_sys_protected.add(found_sys_loc)
      // Debug output
      call Sys_Debug_Print("Ships","    - Protect " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
    endif
  endif

  // Fleet Priority #8 - Hold At Warp Point
  if (not orders_given) or (hold_at_border_warp_pt) then
    set list_count := lst_AI_Fleet_Holding_System.count()
    // Pending
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := lst_AI_Fleet_Holding_System.get(list_index)
        set target_sect_loc := lst_AI_Fleet_Holding_Sector.get(list_index)
        set target_wp_id := lst_AI_Fleet_Holding_WP_ID.get(list_index)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        set target_priority := lst_AI_Fleet_Holding_Location_Priority.get(list_index)
        // Determine the nearest holding point to our fleet
        if (target_dist < (min_dist * target_priority)) then
          set min_dist := target_dist
          set found_sys_loc := target_sys_loc
          set found_sect_loc := target_sect_loc
          set found_wp_id := target_wp_id
          set found_index := list_index
        endif
      endfor
    endif
    // Order our fleet to move to the holding warp point location
    if (found_sys_loc > 0) then
      // Move to the warp point and hold
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, found_sys_loc, found_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships","    - Hold at border warp point in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
      // Estimate the strength of our possible enemies in the destination sector of the warp point
      set wp_dest_sys_loc := lst_AI_Fleet_Holding_Dest_System.get(found_index)
      set wp_dest_sect_loc := Get_Destination_WP_Sector(found_sys_loc, wp_dest_sys_loc)
      set enemy_strength := Calculate_Sector_Strength(wp_dest_sys_loc, wp_dest_sect_loc, FALSE, FALSE, TRUE)
      set enemy_mine_count := Get_Mine_Group_Count(wp_dest_sys_loc, wp_dest_sect_loc)
      // Determine the chance to warp through
      if (fleet_strength > enemy_strength * 2) then
        set max_chance := 30 + (lng_AI_Categorization * 5)
      else
        if (fleet_strength > enemy_strength) then
          set max_chance := 10 + (lng_AI_Categorization * 5)
        else
          if (fleet_strength < (enemy_strength / 2)) then
            set max_chance := (lng_AI_Categorization * 2)
          else
            set max_chance := (lng_AI_Categorization * 5)
          endif
        endif
      endif
      // Consider warping through to probe any potential defenses
      if (orders_given) and (Sys_Get_Random_Long(1, 100) > max_chance) and (not bool_Are_We_Neutral_Player) and (fleet_mine_sweep_count >= enemy_mine_count) then
        set orders_given := Sys_Give_Empire_Fleet_Order_Warp(sys_long_Player_ID, fleet_id, found_wp_id)
        // Debug output
        call Sys_Debug_Print("Ships","    - Transit warp point in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc) + " to probe destination side")
      endif
      // Remove the holding system location
      call lst_AI_Fleet_Holding_System.delete(found_index)
      call lst_AI_Fleet_Holding_Sector.delete(found_index)
      call lst_AI_Fleet_Holding_WP_ID.delete(found_index)
    endif
  endif

  // Fleet Priority #9 - Go to colony in border system
  if (not orders_given) or (order_to_border_sys) then
    set list_count := lst_AI_Border_System.count()
    // Find the nearest colony in a border system to our fleet
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := lst_AI_Border_System.get(list_index)
        set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Is this colony closer than the previous ones?
        if (target_dist < min_dist) then
          set min_dist := target_dist
          set found_sys_loc := target_sys_loc
          set found_sect_loc := target_sect_loc
          set found_index := list_index
        endif
      endfor
      // Order our fleet to the border colony
      if (target_sys_loc > 0) then
        set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        // Remove the border system to visit to avoid duplicate orders
        call lst_AI_Border_System.delete(found_index)
        // Debug output
        call Sys_Debug_Print("Ships","    - Visit border colony in " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
      endif
    endif
  endif

  // Fleet Priority #10 - Train at nearest Fleet Training Complex
  if (not orders_given) then
    set list_count := lst_AI_Fleet_Training_System.count()
    // Find the nearest training location to our fleet
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := lst_AI_Fleet_Training_System.get(list_index)
        set target_sect_loc := lst_AI_Fleet_Training_Sector.get(list_index)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Is this training location closer than the previous ones?
        if (target_dist < min_dist) then
          set min_dist := target_dist
          set found_sys_loc := target_sys_loc
          set found_sect_loc := target_sect_loc
        endif
      endfor
    endif
    // Order our fleet to move to the training location
    if (found_sys_loc > 0) then
      set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, found_sys_loc, found_sect_loc)
      // Debug output
      call Sys_Debug_Print("Ships","    - Train at " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
    endif
  endif

  // Fleet Priority #11 - Go to colony in mutually shared system
  if (not orders_given) then
    set list_count := lst_AI_Mutual_Colony_Systems.count()
    // Find nearest colony in a mutually shared colony system
    if (list_count > 0) then
      for list_index := 1 to list_count do
        set target_sys_loc := lst_AI_Mutual_Colony_Systems.get(list_index)
        set target_sect_loc := Get_A_Colony_Location_In_System(target_sys_loc)
        set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, fleet_sys_loc, fleet_sect_loc, target_sys_loc, target_sect_loc)
        // Is this training location closer than the previous ones?
        if (target_dist < min_dist) then
          set min_dist := target_dist
          set found_sys_loc := target_sys_loc
          set found_sect_loc := target_sect_loc
          set found_index := list_index
        endif
      endfor
      // Order our fleet to the selected colony
      if (target_sys_loc > 0) then
        set orders_given := Sys_Give_Empire_Fleet_Order_Moveto(sys_long_Player_ID, fleet_id, target_sys_loc, target_sect_loc)
        // Remove the mutual colony system to visit to avoid duplicate orders
        call lst_AI_Mutual_Colony_Systems.delete(found_index)
        // Debug output
        call Sys_Debug_Print("Ships","    - Visit colony in mutually shared " + Sys_Get_Solar_System_Name(found_sys_loc) + " System " + Convert_Sector_To_String(found_sect_loc))
      endif
    endif
  endif

  return orders_given
end

//------------------------------------------------------------------------
// Get_Target_To_Attack
//------------------------------------------------------------------------
function Get_Target_To_Attack returns long
params
  location_type:             long
  our_max_targets:           long
  our_sys_loc:               long
  our_sect_loc:              long
  our_movement:              long
  our_strength:              long
  our_obj_type:              long
  our_mine_sweep_count:      long
  our_max_atk_dist:          long
  consider_capture:          boolean
  consider_retreat:          boolean
  consider_mines:            boolean
  same_sys_only:             boolean
  single_target_only:        boolean
vars
  list_count:                long
  list_index:                long
  lst_trg_obj_id:            longlist
  lst_trg_sys_loc:           longlist
  lst_trg_sect_loc:          longlist
  lst_trg_obj_strength:      longlist
  lst_trg_obj_movement:      longlist
  lst_trg_obj_strat_value:   longlist
  lst_trg_obj_ship_count:    longlist
  target_sys_loc:            long
  target_sect_loc:           long
  target_obj_id:             long
  target_obj_type:           long
  target_obj_owner:          long
  target_strength:           long
  target_strength_mod:       long := 100
  target_retreat_mod:        long := 125
  target_success_mod:        long := 100
  target_dist:               long
  target_movement:           long
  target_strategic_value:    long
  target_ship_count:         long
  target_mine_count:         long
  target_cargo:              long
  target_atk_pts:            long
  target_index:              long
  target_type:               string
  lst_target_index:          longlist
  lst_target_atk_pts:        longlist
  target_mega_evil:          boolean
  target_human:              boolean
  skip_target:               boolean
  attack_target:             boolean
  flag_retreat:              boolean
  send_message:              boolean := FALSE
  combat_defend:             boolean
  combat_attack:             boolean
begin

  // Get our target's details depending on the location type
  case (location_type)
    LOCATION_TYPE_DEFENSE:
      set list_count := lst_AI_Defense_Location_System.count()
      // Debug output
      call Sys_Debug_Print("Ships", "    - Defense Locations Count = " + Sys_Convert_Long_To_String(list_count))
      // Make a list of targets from our Defense Locations
      if (list_count > 0) then
        set target_type := "(Defense Location)"
        for list_index := 1 to list_count do
          if (not same_sys_only) or (lst_AI_Defense_Location_System.get(list_index) = our_sys_loc) then
            call lst_trg_sys_loc.add(lst_AI_Defense_Location_System.get(list_index))
            call lst_trg_sect_loc.add(lst_AI_Defense_Location_Sector.get(list_index))
            call lst_trg_obj_id.add(lst_AI_Defense_Location_Ship_ID.get(list_index))
            call lst_trg_obj_strength.add(lst_AI_Defense_Location_Strength.get(list_index))
            call lst_trg_obj_ship_count.add(lst_AI_Defense_Location_Ship_Count.get(list_index))
            call lst_trg_obj_movement.add(lst_AI_Defense_Location_Ship_Min_Move.get(list_index))
            call lst_trg_obj_strat_value.add(lst_AI_Defense_Location_Strategic_Value.get(list_index))
          endif
        endfor
      endif
      // Modifiers
      set target_success_mod := 100
      set combat_defend := TRUE
    LOCATION_TYPE_ATTACK:
      set list_count := lst_AI_Attack_Location_System.count()
      // Debug output
      call Sys_Debug_Print("Ships", "    - Attack Locations Count = " + Sys_Convert_Long_To_String(list_count))
      // Make a list of targets from our Attack Locations
      if (list_count > 0) then
        set target_type := "(Attack Location)"
        for list_index := 1 to list_count do
          if (not same_sys_only) or (lst_AI_Attack_Location_System.get(list_index) = our_sys_loc) then
            call lst_trg_sys_loc.add(lst_AI_Attack_Location_System.get(list_index))
            call lst_trg_sect_loc.add(lst_AI_Attack_Location_Sector.get(list_index))
            call lst_trg_obj_id.add(lst_AI_Attack_Location_Ship_ID.get(list_index))
            call lst_trg_obj_strength.add(lst_AI_Attack_Location_Strength.get(list_index))
            call lst_trg_obj_ship_count.add(lst_AI_Attack_Location_Ship_Count.get(list_index))
            call lst_trg_obj_movement.add(0)
            call lst_trg_obj_strat_value.add(lst_AI_Attack_Location_Strategic_Value.get(list_index))
          endif
        endfor
      endif
      // Modifiers
      set target_success_mod := 100
      set combat_attack := TRUE
    LOCATION_TYPE_NEARBY_ENEMY:
      set list_count := lst_AI_Nearby_Enemy_Location_System.count()
      // Debug output
      call Sys_Debug_Print("Ships", "    - Nearby Enemy Locations = " + Sys_Convert_Long_To_String(list_count))
      // Make a list of targets from our Nearby Enemy Locations
      if (list_count > 0) then
        set target_type := "(Nearby Enemy Location)"
        for list_index := 1 to list_count do
          if (not same_sys_only) or (lst_AI_Nearby_Enemy_Location_System.get(list_index) = our_sys_loc) then
            call lst_trg_sys_loc.add(lst_AI_Nearby_Enemy_Location_System.get(list_index))
            call lst_trg_sect_loc.add(lst_AI_Nearby_Enemy_Location_Sector.get(list_index))
            call lst_trg_obj_id.add(lst_AI_Nearby_Enemy_Location_Ship_ID.get(list_index))
            call lst_trg_obj_strength.add(lst_AI_Nearby_Enemy_Location_Strength.get(list_index))
            call lst_trg_obj_ship_count.add(lst_AI_Nearby_Enemy_Location_Ship_Count.get(list_index))
            call lst_trg_obj_movement.add(lst_AI_Nearby_Enemy_Location_Ship_Min_Move.get(list_index))
            call lst_trg_obj_strat_value.add(lst_AI_Nearby_Enemy_Location_Strategic_Value.get(list_index))
          endif
        endfor
      endif
      // Modifiers
      set target_success_mod := 100
      set combat_attack := TRUE
  endcase

  // Go through our list of targets and assign points based on several factors
  set list_count := lst_trg_sys_loc.count()
  set list_index := 0

  // Debug output
  call Sys_Debug_Print("Ships", "    - Potential Targets " + target_type)

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Reset attack flag
      set attack_target := FALSE
      set skip_target := FALSE
      set target_atk_pts := 0
      set target_strength_mod := 100
      set target_retreat_mod := 125
      // Get more target details
      set target_sys_loc := lst_trg_sys_loc.get(list_index)
      set target_sect_loc := lst_trg_sect_loc.get(list_index)
      set target_obj_id := lst_trg_obj_id.get(list_index)
      set target_obj_owner := Sys_Get_Space_Object_Owner(target_obj_id)
      set target_obj_type := Sys_Get_Space_Object_Type(target_obj_id)
      set target_strength := lst_trg_obj_strength.get(list_index)
      set target_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, our_sys_loc, our_sect_loc, target_sys_loc, target_sect_loc)
      set target_movement := lst_trg_obj_movement.get(list_index)
      set target_strategic_value := lst_trg_obj_strat_value.get(list_index)
      set target_ship_count := lst_trg_obj_ship_count.get(list_index)
      set target_mine_count := Get_Mine_Group_Count(target_sys_loc, target_sect_loc)

      // Reduce target strength modifier if the player is the mega evil player or the human player in an AI team game
      if Sys_Empire_Politics_Is_Player_The_Ultimate_Evil(sys_long_Player_ID, target_obj_owner) or (not Sys_Empire_Politics_Is_Player_On_Our_Team(sys_long_Player_ID, target_obj_owner)) then
        set target_strength_mod := target_strength_mod - 10
        set target_retreat_mod := target_retreat_mod + 10
      endif

      // Reduce target strength modifier if the player is our primary enemy
      if (lng_Politics_Primary_Enemy = target_obj_owner) then
        set target_strength_mod := target_strength_mod - 10
      else
        // Increase target strength modifier for lower priority enemies
        set target_strength_mod := target_strength_mod + 10
      endif

      // Reduce target strength modifier if we are a stronger player
      if (lst_Politics_Fear_Towards_Player.get(target_obj_owner) >= 10) then
        set target_strength_mod := target_strength_mod - 10
        set target_retreat_mod := target_retreat_mod + 10
      endif

      // Adjust the target strength
      set target_strength := Sys_Trunc(target_strength * target_strength_mod / 100)

      // Debug output
      call Sys_Debug_Print("Ships", "      - Target = " + Sys_Get_Space_Object_Name(target_obj_id) + " (" + Sys_Convert_Long_To_String(target_strength_mod) + "/" + Sys_Convert_Long_To_String(target_retreat_mod) + ")")

      // Don't consider a target of a player we said we wouldn't attack (sometimes at least)
      if (lst_AI_Temp_Stop_Attack_vs_Empire.indexof(target_obj_owner) > 0) then
        if (Sys_Get_Random_Long(1,  2 + lng_AI_Categorization) < 3) then
          set skip_target := TRUE
          // Debug output
          call Sys_Debug_Print("Ships", "        - Accepted a request that we wouldn't attack " + Sys_Empire_Get_Empire_Name(target_obj_owner))
        else
          // Debug output
          call Sys_Debug_Print("Ships", "        - Accepted a request that we wouldn't attack " + Sys_Empire_Get_Empire_Name(target_obj_owner) + " but lied!")
        endif
      endif

      // Don't consider attacking in a system we said we wouldn't attack in (sometimes at least)
      if (lst_AI_Temp_Stop_Attack_in_System.indexof(target_sys_loc) > 0) then
        if (Sys_Get_Random_Long(1,  2 + lng_AI_Categorization) < 3) then
          set skip_target := TRUE
          // Debug output
          call Sys_Debug_Print("Ships", "        - Accepted a request that we wouldn't attack " + Sys_Get_Solar_System_Name(target_sys_loc) + " System")
        else
          // Debug output
          call Sys_Debug_Print("Ships", "        - Accepted a request that we wouldn't attack " + Sys_Get_Solar_System_Name(target_sys_loc) + " System but lied!")
        endif
      endif

      // Don't consider a distant target
      if (our_max_atk_dist < target_dist) and (not skip_target) then
        set skip_target := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "        - Too far " + "(" + Sys_Convert_Long_To_String(target_dist) + ")")
      endif

      // Don't consider a stronger target
      if (our_strength < target_strength) and (not skip_target) then
        set skip_target := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "        - Target too strong (" + Sys_Convert_Long_To_String(our_strength) + "/" + Sys_Convert_Long_To_String(target_strength) + ")")
      endif

      // Don't consider multiple ship targets if we're targeting single ships only
      if (single_target_only) then
        if (target_ship_count > 1) then
          set skip_target := TRUE
          // Debug output
          call Sys_Debug_Print("Ships", "        - More than 1 target (" + Sys_Convert_Long_To_String(target_ship_count) + ")")
        endif
      endif

      // Don't consider the target if it's a Mine Group
      if (target_obj_type = SPACE_OBJECT_TYPE_UNITGROUP) and (not skip_target) then
        if (Get_Unit_Group_Type(target_obj_id) = "Mine") then
          set skip_target := TRUE
          // Debug output
          call Sys_Debug_Print("Ships", "        - Target is mine group")
        endif
      endif

      // If retreat is a possibility, then consider it
      if (consider_retreat) then
        if (our_sys_loc = target_sys_loc) and (our_movement < target_dist) then
          if (our_strength < Sys_Trunc(target_strength * target_retreat_mod / 100)) then
            set skip_target := TRUE
            set flag_retreat := TRUE
            call gbl_lst_target_loc_type.add(location_type)
            call gbl_lst_target_index.add(list_index)
            call gbl_lst_target_obj_id.add(target_obj_id)
            call gbl_lst_target_sys_loc.add(target_sys_loc)
            call gbl_lst_target_sect_loc.add(target_sect_loc)
          endif
        endif
      endif

      // Don't attack if are considering mines and don't have the capability to sweep them
      if (consider_mines) and (not skip_target) then
        if (our_mine_sweep_count < target_mine_count) then
          set skip_target := TRUE
          // Debug output
          call Sys_Debug_Print("Ships", "        - Can't target due to minefield")
        endif
      endif

      // Assign attack points for each valid target
      if (not skip_target) then

        // Add strategic value
        set target_atk_pts := target_atk_pts + target_strategic_value

        if (combat_defend) then
          // More emphasis for our proximity to the target
          if (target_dist < our_movement) then
            set target_atk_pts := target_atk_pts + Sys_Trunc(100 - (target_dist * 5.0))
            set target_atk_pts := target_atk_pts + Sys_Trunc(target_strength / 2000.0)
          else
            // More emphasis on our strength versus the target
            set target_atk_pts := target_atk_pts + Sys_Trunc(100 - (target_dist * 2.5))
            set target_atk_pts := target_atk_pts + Sys_Trunc(target_strength / 1000.0)
          endif
        endif

        // Special conditions to fulfill requests
        if (lst_AI_Give_Military_Assistance_in_System.indexof(target_sys_loc) > 0) or (lst_AI_Give_Military_Assistance_vs_Empire.indexof(target_obj_owner) > 0) then
          set target_atk_pts := target_atk_pts + 50
          // Potentially send a message to our allies or request
          set send_message := TRUE
        endif

        // Special conditions for enemy ships
        if (target_obj_type = SPACE_OBJECT_TYPE_SHIP) then
          // Don't waste effort attacking ships that are faster and unarmed
          if (target_movement > our_movement + 3) or ((target_movement > our_movement + 1) + (Sys_Get_Space_Object_Total_Weapon_Damage(target_obj_id) = 0)) then
            set target_atk_pts := 0
          endif
        endif

        // Special conditions for enemy unit groups
        if (target_obj_type = SPACE_OBJECT_TYPE_UNITGROUP) then
          // Don't waste effort attacking unit groups that are much weaker
          if (our_strength > target_strength * 10) and (not single_target_only) then
            set target_atk_pts := 0
            // Debug output
            call Sys_Debug_Print("Ships", "        - Skipped attacking weak unit group")
          endif
        endif

        // Special attack conditions for planets
        if (target_obj_type = SPACE_OBJECT_TYPE_PLANET) then
          // Modify for distance
          if (target_dist < our_movement) then
            set target_atk_pts := target_atk_pts + 50
          else
            set target_atk_pts := 25 - ((target_dist - our_movement) * 2)
          endif
          // Modify target attack points for types of facilities present
          set target_atk_pts := target_atk_pts + Sys_Divide_Long(target_strategic_value, 2)
          // Capture modifier
          if (consider_capture) then
            // More target points for less resistance
            if (Sys_Get_Space_Object_Total_Weapon_Damage(target_obj_id) < our_strength * 0.1) then
              set target_atk_pts := target_atk_pts + 25
            endif
          endif
          // Random factor to reduce predictability of computer player targets
          if (target_strategic_value >= 25) and (target_strategic_value <= 75) then
            If (Sys_Get_Random_Long(1, 4) = 1) or (our_strength > (target_strength * 2)) then
              set target_atk_pts := Sys_Multiply_Long(target_atk_pts, 2)
              // Debug output
              call Sys_Debug_Print("Ships", "        - Boosted target value of a moderate target to vary attack")
            endif
          endif
        endif
      else
        set target_atk_pts := 0
      endif
      // Add to target list
      if (target_atk_pts > 0) then
        call lst_target_index.add(list_index)
        call lst_target_atk_pts.add(target_atk_pts)
        // Debug output
        call Sys_Debug_Print("Ships", "        - Target Ok = " + Sys_Get_Space_Object_Name(target_obj_id) + "; Atk Pts = " + Sys_Convert_Long_To_String(target_atk_pts) + "; Strength = " + Sys_Convert_Long_To_String(target_strength) + "; Strategic value = " + Sys_Convert_Long_To_String(target_strategic_value))
        // Add only one target if we are exceeding our turn's movement to attack
        if (target_dist > our_movement) then
          set our_max_targets := 1
        endif
      endif
      exitwhen (list_index >= list_count) or (flag_retreat)
    endloop
  endif

  // How many targets do we have?
  set list_count := lst_target_index.count()

  // Special flags
  if (flag_retreat) then
    set list_count := -1
  endif

  // Sort our perspective target list by target points and add to our list of targets
  if (list_count > 0) then
    call Sys_Prepare_For_List_Sort()
    call Sys_Set_List_Sort_Field(1, lst_target_index)
    call Sys_Set_List_Sort_Field(2, lst_target_atk_pts)
    call Sys_Add_List_Sort_Sort_Column(2, FALSE)
    call Sys_Execute_List_Sort()

    set list_count := Sys_Min_Long(list_count, our_max_targets)

    for list_index := 1 to list_count do
      set target_index := lst_target_index.get(list_index)
      // Add the target to our list
      call gbl_lst_target_loc_type.add(location_type)
      call gbl_lst_target_index.add(target_index)
      call gbl_lst_target_obj_id.add(lst_trg_obj_id.get(target_index))
      call gbl_lst_target_sys_loc.add(lst_trg_sys_loc.get(target_index))
      call gbl_lst_target_sect_loc.add(lst_trg_sect_loc.get(target_index))
      // Debug output
      call Sys_Debug_Print("Ships", "    - Selected Target = " + Sys_Get_Space_Object_Name(lst_trg_obj_id.get(target_index)))
    endfor
  else
    if (list_count = -1) then
      // Debug output
      call Sys_Debug_Print("Ships", "      - Retreat to colony")
    else
      // Debug output
      call Sys_Debug_Print("Ships", "      - No targets identified")
    endif
  endif

  return list_count
end

//------------------------------------------------------------------------